Replace the wallet policy AST relative pointers with native pointers
What changed, and why it matters
This commit is a code cleanup in Ledger's Bitcoin app. It replaces a memory-saving 'relative pointer' scheme with ordinary C pointers in the wallet-policy data structures. The change removes several hundred lines of pointer-conversion code and adds one compile-time check to make sure key-expression structures stay properly aligned when allocated back-to-back. There is no direct evidence in the commit that it fixes an active security bug; it reads as a maintainability/refactoring change to reduce complexity on newer Ledger devices that have more RAM.
Treat as a normal refactoring commit. Run the existing unit tests and on-device fuzzing/validation suite to confirm that parsing, script generation, taptree hashing, and signing still behave identically. Review the new _Static_assert and confirm that buffer_alloc alignment is indeed 4 bytes on all supported targets. No urgent security response is indicated by the diff itself.
Security signals we found
Large-scale pointer model change in security-critical parsing/rendering/signing code
Removal of a 16-bit relative-pointer encoding that previously limited offsets to 65535 bytes
Addition of a static assertion enforcing alignment of policy_node_keyexpr_t
No explicit security relevance, CVE, or bug-fix framing in commit message
Evidence from the diff
The patch removes the DEFINE_REL_PTR macro family and all r_ / i_ / isnull_ accessor functions for 16-bit relative pointers in the wallet policy AST. Node fields are changed from rptr__t to native pointers (e.g., policy_node_t , policy_node_keyexpr_t , musig_aggr_key_info_t , uint16_t ). All call sites are updated to use direct pointer access. A new _Static_assert in wallet.c checks that sizeof(policy_node_keyexpr_t) is a multiple of 4, codifying an implicit alignment assumption relied on by the multi()/sortedmulti() array allocation. The commit message frames this as a complexity-vs-RAM trade-off, not as a security fix.
Changed components
src/common/wallet.hsrc/common/wallet.csrc/common/cleartext.csrc/common/cleartext_match.csrc/handler/lib/policy.csrc/handler/sign_psbt/init_global_state.csrc/handler/sign_psbt/musig_signing.csrc/handler/sign_psbt/sign_input.cspecs/bip388/gen.pyunit-tests/test_wallet.cInspect captured patch +358 / −507
### specs/bip388/gen.py
@@ -425,8 +425,8 @@ def fresh(self, base: str) -> str:
def _sub_child_expr(struct: str, t: str, i: int) -> str:
if struct == "policy_node_with_script_t":
- return f"r_policy_node(&{t}->script)"
- return f"r_policy_node(&{t}->scripts[{i}])" # script2 / script3
+ return f"{t}->script"
+ return f"{t}->scripts[{i}]" # script2 / script3
def _classify_sub(ctx: _Ctx, node_var: str, name: str) -> None:
@@ -446,13 +446,13 @@ def _peel_wrappers(ctx: _Ctx, node_var: str, wrappers: list[str]) -> str:
w = ctx.fresh("w")
ctx.body.append(f"const policy_node_with_script_t *{w} = (const policy_node_with_script_t *) {node_var};")
c2 = ctx.fresh("c")
- ctx.body.append(f"const policy_node_t *{c2} = r_policy_node(&{w}->script);")
+ ctx.body.append(f"const policy_node_t *{c2} = {w}->script;")
node_var = c2
return node_var
def _handle_key_arg(ctx: _Ctx, arg: Any, t: str) -> None:
- key_expr = f"r_policy_node_keyexpr(&{t}->key)"
+ key_expr = f"{t}->key"
if arg[0] == "binding" and arg[2] == "KEY":
k = ctx.fresh("k")
ctx.body.append(f"const policy_node_keyexpr_t *{k} = {key_expr};")
@@ -464,7 +464,7 @@ def _handle_key_arg(ctx: _Ctx, arg: Any, t: str) -> None:
ctx.body.append(f"const policy_node_keyexpr_t *{k} = {key_expr};")
ctx.body.append(f"if ({k}->type != KEY_EXPRESSION_MUSIG) break;")
mi = ctx.fresh("mi")
- ctx.body.append(f"const musig_aggr_key_info_t *{mi} = r_musig_aggr_key_info(&{k}->m.musig_info);")
+ ctx.body.append(f"const musig_aggr_key_info_t *{mi} = {k}->m.musig_info;")
ts, ks = ctx.bidx[arg[1]], ctx.bidx[arg[2]]
ctx.binds.append(f"set_binding_number(&out->bindings, {ts}, {mi}->n);")
ctx.binds.append(f"set_binding_keys(&out->bindings, {ks}, {k}, 1);")
@@ -486,7 +486,7 @@ def _handle_arg(ctx: _Ctx, arg: Any, ak: str, struct: str, t: str, i: int) -> No
if not (arg[0] == "binding" and arg[2] == "KEYS"):
raise ValueError(f"unexpected arg {arg!r} in KeyList position")
ka = ctx.fresh("ka")
- ctx.body.append(f"const policy_node_keyexpr_t *{ka} = r_policy_node_keyexpr(&{t}->keys);")
+ ctx.body.append(f"const policy_node_keyexpr_t *{ka} = {t}->keys;")
slot = ctx.bidx[arg[1]]
ctx.binds.append(f"set_binding_keys(&out->bindings, {slot}, {ka}, {t}->n);")
elif ak == "SUB":
@@ -524,10 +524,10 @@ def _lower(ctx: _Ctx, pat: Pattern, node_expr: str) -> None:
# the $leaves taptree. A 1-arg tr matches only a leaf-less taproot.
_handle_key_arg(ctx, pat.args[0], t)
if len(pat.args) == 1:
- ctx.body.append(f"if (!isnull_policy_node_tree(&{t}->tree)) break;")
+ ctx.body.append(f"if ({t}->tree != NULL) break;")
else:
- ctx.body.append(f"if (isnull_policy_node_tree(&{t}->tree)) break;")
- ctx.binds.append(f"out->taptree = r_policy_node_tree(&{t}->tree);")
+ ctx.body.append(f"if ({t}->tree == NULL) break;")
+ ctx.binds.append(f"out->taptree = {t}->tree;")
return
for i, arg in enumerate(pat.args):
### src/common/cleartext.c
@@ -235,8 +235,8 @@ static uint64_t key_orderings_count(const policy_node_t *root, bool *out_canonic
members[0] = k->k.key_index;
n_members = 1;
} else {
- const musig_aggr_key_info_t *ai = r_musig_aggr_key_info(&k->m.musig_info);
- const uint16_t *ak = r_uint16(&ai->key_indexes);
+ const musig_aggr_key_info_t *ai = k->m.musig_info;
+ const uint16_t *ak = ai->key_indexes;
n_members = ai->n;
for (uint16_t j = 0; j < n_members; j++) members[j] = ak[j];
}
@@ -273,7 +273,7 @@ static uint64_t key_orderings_count(const policy_node_t *root, bool *out_canonic
static uint16_t keys_member_count(const ct_value_t *v) {
if (v->u.keys.n == 1 && v->u.keys.array != NULL &&
v->u.keys.array[0].type == KEY_EXPRESSION_MUSIG) {
- return r_musig_aggr_key_info(&v->u.keys.array[0].m.musig_info)->n;
+ return v->u.keys.array[0].m.musig_info->n;
}
return v->u.keys.n;
}
@@ -282,8 +282,8 @@ static uint16_t keys_member_count(const ct_value_t *v) {
static uint32_t keys_member_index(const ct_value_t *v, uint16_t j) {
if (v->u.keys.n == 1 && v->u.keys.array != NULL &&
v->u.keys.array[0].type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *mi = r_musig_aggr_key_info(&v->u.keys.array[0].m.musig_info);
- return r_uint16(&mi->key_indexes)[j];
+ const musig_aggr_key_info_t *mi = v->u.keys.array[0].m.musig_info;
+ return mi->key_indexes[j];
}
return v->u.keys.array[j].k.key_index;
}
@@ -300,13 +300,13 @@ static int compare_uint32(uint32_t left, uint32_t right) {
static int compare_musig_keyexprs(const policy_node_keyexpr_t *left,
const policy_node_keyexpr_t *right) {
- const musig_aggr_key_info_t *left_info = r_musig_aggr_key_info(&left->m.musig_info);
- const musig_aggr_key_info_t *right_info = r_musig_aggr_key_info(&right->m.musig_info);
+ const musig_aggr_key_info_t *left_info = left->m.musig_info;
+ const musig_aggr_key_info_t *right_info = right->m.musig_info;
int order = compare_uint16(left_info->n, right_info->n);
if (order != 0) return order;
- const uint16_t *left_indexes = r_uint16(&left_info->key_indexes);
- const uint16_t *right_indexes = r_uint16(&right_info->key_indexes);
+ const uint16_t *left_indexes = left_info->key_indexes;
+ const uint16_t *right_indexes = right_info->key_indexes;
for (uint16_t i = 0; i < left_info->n; i++) {
order = compare_uint16(left_indexes[i], right_indexes[i]);
if (order != 0) return order;
@@ -451,8 +451,8 @@ static int append_keyexpr(char *out, size_t cap, size_t *off, const policy_node_
return append_str(out, cap, off, buf);
}
// KEY_EXPRESSION_MUSIG: "musig(@a,@b,@c)"
- const musig_aggr_key_info_t *mi = r_musig_aggr_key_info(&key->m.musig_info);
- const uint16_t *idx = r_uint16(&mi->key_indexes);
+ const musig_aggr_key_info_t *mi = key->m.musig_info;
+ const uint16_t *idx = mi->key_indexes;
if (append_str(out, cap, off, "musig(") < 0) return -1;
for (uint16_t i = 0; i < mi->n; i++) {
char buf[8];
@@ -475,8 +475,8 @@ static int append_keys_list(char *out,
// tr(musig(...)) forms). In that case render the inner keys as a flat
// Oxford-comma list (without "musig(...)" wrapping).
if (n == 1 && keys->type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *mi = r_musig_aggr_key_info(&keys->m.musig_info);
- const uint16_t *idx = r_uint16(&mi->key_indexes);
+ const musig_aggr_key_info_t *mi = keys->m.musig_info;
+ const uint16_t *idx = mi->key_indexes;
uint16_t m = mi->n;
for (uint16_t i = 0; i < m; i++) {
if (i > 0) {
@@ -710,11 +710,11 @@ static int collect_leaves(const policy_node_tree_t *tree,
if (tree == NULL) return 0;
if (tree->is_leaf) {
if (*n >= max) return -1;
- out[(*n)++] = r_policy_node(&tree->script);
+ out[(*n)++] = tree->script;
return 0;
}
- if (collect_leaves(r_policy_node_tree(&tree->left_tree), out, n, max) < 0) return -1;
- return collect_leaves(r_policy_node_tree(&tree->right_tree), out, n, max);
+ if (collect_leaves(tree->left_tree, out, n, max) < 0) return -1;
+ return collect_leaves(tree->right_tree, out, n, max);
}
// ---------------------------------------------------------------------------
### src/common/cleartext_match.c
@@ -15,7 +15,7 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_PKH) break;
const policy_node_with_key_t *ct_n1 = (const policy_node_with_key_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_NORMAL) break;
set_binding_key(&out->bindings, 0, ct_k2);
out->bindings.n = 1;
@@ -27,7 +27,7 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_WPKH) break;
const policy_node_with_key_t *ct_n1 = (const policy_node_with_key_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_NORMAL) break;
set_binding_key(&out->bindings, 0, ct_k2);
out->bindings.n = 1;
@@ -38,10 +38,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_SH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_WPKH) break;
const policy_node_with_key_t *ct_n3 = (const policy_node_with_key_t *) ct_c2;
- const policy_node_keyexpr_t *ct_k4 = r_policy_node_keyexpr(&ct_n3->key);
+ const policy_node_keyexpr_t *ct_k4 = ct_n3->key;
if (ct_k4->type != KEY_EXPRESSION_NORMAL) break;
set_binding_key(&out->bindings, 0, ct_k4);
out->bindings.n = 1;
@@ -53,10 +53,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_SH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_MULTI) break;
const policy_node_multisig_t *ct_n3 = (const policy_node_multisig_t *) ct_c2;
- const policy_node_keyexpr_t *ct_ka4 = r_policy_node_keyexpr(&ct_n3->keys);
+ const policy_node_keyexpr_t *ct_ka4 = ct_n3->keys;
set_binding_number(&out->bindings, 0, ct_n3->k);
set_binding_keys(&out->bindings, 1, ct_ka4, ct_n3->n);
out->bindings.n = 2;
@@ -67,10 +67,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_SH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_SORTEDMULTI) break;
const policy_node_multisig_t *ct_n3 = (const policy_node_multisig_t *) ct_c2;
- const policy_node_keyexpr_t *ct_ka4 = r_policy_node_keyexpr(&ct_n3->keys);
+ const policy_node_keyexpr_t *ct_ka4 = ct_n3->keys;
set_binding_number(&out->bindings, 0, ct_n3->k);
set_binding_keys(&out->bindings, 1, ct_ka4, ct_n3->n);
out->bindings.n = 2;
@@ -81,10 +81,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_WSH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_MULTI) break;
const policy_node_multisig_t *ct_n3 = (const policy_node_multisig_t *) ct_c2;
- const policy_node_keyexpr_t *ct_ka4 = r_policy_node_keyexpr(&ct_n3->keys);
+ const policy_node_keyexpr_t *ct_ka4 = ct_n3->keys;
set_binding_number(&out->bindings, 0, ct_n3->k);
set_binding_keys(&out->bindings, 1, ct_ka4, ct_n3->n);
out->bindings.n = 2;
@@ -95,10 +95,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_WSH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_SORTEDMULTI) break;
const policy_node_multisig_t *ct_n3 = (const policy_node_multisig_t *) ct_c2;
- const policy_node_keyexpr_t *ct_ka4 = r_policy_node_keyexpr(&ct_n3->keys);
+ const policy_node_keyexpr_t *ct_ka4 = ct_n3->keys;
set_binding_number(&out->bindings, 0, ct_n3->k);
set_binding_keys(&out->bindings, 1, ct_ka4, ct_n3->n);
out->bindings.n = 2;
@@ -109,13 +109,13 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_SH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_WSH) break;
const policy_node_with_script_t *ct_n3 = (const policy_node_with_script_t *) ct_c2;
- const policy_node_t *ct_c4 = r_policy_node(&ct_n3->script);
+ const policy_node_t *ct_c4 = ct_n3->script;
if (ct_c4 == NULL || ct_c4->type != TOKEN_MULTI) break;
const policy_node_multisig_t *ct_n5 = (const policy_node_multisig_t *) ct_c4;
- const policy_node_keyexpr_t *ct_ka6 = r_policy_node_keyexpr(&ct_n5->keys);
+ const policy_node_keyexpr_t *ct_ka6 = ct_n5->keys;
set_binding_number(&out->bindings, 0, ct_n5->k);
set_binding_keys(&out->bindings, 1, ct_ka6, ct_n5->n);
out->bindings.n = 2;
@@ -126,13 +126,13 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_SH) break;
const policy_node_with_script_t *ct_n1 = (const policy_node_with_script_t *) root;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->script);
+ const policy_node_t *ct_c2 = ct_n1->script;
if (ct_c2 == NULL || ct_c2->type != TOKEN_WSH) break;
const policy_node_with_script_t *ct_n3 = (const policy_node_with_script_t *) ct_c2;
- const policy_node_t *ct_c4 = r_policy_node(&ct_n3->script);
+ const policy_node_t *ct_c4 = ct_n3->script;
if (ct_c4 == NULL || ct_c4->type != TOKEN_SORTEDMULTI) break;
const policy_node_multisig_t *ct_n5 = (const policy_node_multisig_t *) ct_c4;
- const policy_node_keyexpr_t *ct_ka6 = r_policy_node_keyexpr(&ct_n5->keys);
+ const policy_node_keyexpr_t *ct_ka6 = ct_n5->keys;
set_binding_number(&out->bindings, 0, ct_n5->k);
set_binding_keys(&out->bindings, 1, ct_ka6, ct_n5->n);
out->bindings.n = 2;
@@ -143,10 +143,10 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_TR) break;
const policy_node_tr_t *ct_n1 = (const policy_node_tr_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_MUSIG) break;
- const musig_aggr_key_info_t *ct_mi3 = r_musig_aggr_key_info(&ct_k2->m.musig_info);
- if (!isnull_policy_node_tree(&ct_n1->tree)) break;
+ const musig_aggr_key_info_t *ct_mi3 = ct_k2->m.musig_info;
+ if (ct_n1->tree != NULL) break;
set_binding_number(&out->bindings, 0, ct_mi3->n);
set_binding_keys(&out->bindings, 1, ct_k2, 1);
out->bindings.n = 2;
@@ -158,9 +158,9 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_TR) break;
const policy_node_tr_t *ct_n1 = (const policy_node_tr_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_NORMAL) break;
- if (!isnull_policy_node_tree(&ct_n1->tree)) break;
+ if (ct_n1->tree != NULL) break;
set_binding_key(&out->bindings, 0, ct_k2);
out->bindings.n = 1;
out->cls = DC_TAPROOT_KEY_ONLY;
@@ -171,11 +171,11 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_TR) break;
const policy_node_tr_t *ct_n1 = (const policy_node_tr_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_NORMAL) break;
- if (isnull_policy_node_tree(&ct_n1->tree)) break;
+ if (ct_n1->tree == NULL) break;
set_binding_key(&out->bindings, 0, ct_k2);
- out->taptree = r_policy_node_tree(&ct_n1->tree);
+ out->taptree = ct_n1->tree;
out->bindings.n = 1;
out->cls = DC_TAPROOT;
return true;
@@ -185,13 +185,13 @@ bool match_top_level(const policy_node_t *root, ct_top_match_t *out) {
do {
if (root == NULL || root->type != TOKEN_TR) break;
const policy_node_tr_t *ct_n1 = (const policy_node_tr_t *) root;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_MUSIG) break;
- const musig_aggr_key_info_t *ct_mi3 = r_musig_aggr_key_info(&ct_k2->m.musig_info);
- if (isnull_policy_node_tree(&ct_n1->tree)) break;
+ const musig_aggr_key_info_t *ct_mi3 = ct_k2->m.musig_info;
+ if (ct_n1->tree == NULL) break;
set_binding_number(&out->bindings, 0, ct_mi3->n);
set_binding_keys(&out->bindings, 1, ct_k2, 1);
- out->taptree = r_policy_node_tree(&ct_n1->tree);
+ out->taptree = ct_n1->tree;
out->bindings.n = 2;
out->cls = DC_TAPROOT_MUSIG;
return true;
@@ -212,7 +212,7 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_PK) break;
const policy_node_with_key_t *ct_n1 = (const policy_node_with_key_t *) leaf_script;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_NORMAL) break;
set_binding_key(&out->bindings, 0, ct_k2);
out->bindings.n = 1;
@@ -224,18 +224,18 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_AND_V) break;
const policy_node_with_script2_t *ct_n1 = (const policy_node_with_script2_t *) leaf_script;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->scripts[0]);
+ const policy_node_t *ct_c2 = ct_n1->scripts[0];
if (ct_c2 == NULL || ct_c2->type != TOKEN_V) break;
const policy_node_with_script_t *ct_w3 = (const policy_node_with_script_t *) ct_c2;
- const policy_node_t *ct_c4 = r_policy_node(&ct_w3->script);
+ const policy_node_t *ct_c4 = ct_w3->script;
if (ct_c4 == NULL || ct_c4->type != TOKEN_PK) break;
const policy_node_with_key_t *ct_n5 = (const policy_node_with_key_t *) ct_c4;
- const policy_node_keyexpr_t *ct_k6 = r_policy_node_keyexpr(&ct_n5->key);
+ const policy_node_keyexpr_t *ct_k6 = ct_n5->key;
if (ct_k6->type != KEY_EXPRESSION_NORMAL) break;
- const policy_node_t *ct_c7 = r_policy_node(&ct_n1->scripts[1]);
+ const policy_node_t *ct_c7 = ct_n1->scripts[1];
if (ct_c7 == NULL || ct_c7->type != TOKEN_PK) break;
const policy_node_with_key_t *ct_n8 = (const policy_node_with_key_t *) ct_c7;
- const policy_node_keyexpr_t *ct_k9 = r_policy_node_keyexpr(&ct_n8->key);
+ const policy_node_keyexpr_t *ct_k9 = ct_n8->key;
if (ct_k9->type != KEY_EXPRESSION_NORMAL) break;
set_binding_key(&out->bindings, 0, ct_k6);
set_binding_key(&out->bindings, 1, ct_k9);
@@ -248,7 +248,7 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_SORTEDMULTI_A) break;
const policy_node_multisig_t *ct_n1 = (const policy_node_multisig_t *) leaf_script;
- const policy_node_keyexpr_t *ct_ka2 = r_policy_node_keyexpr(&ct_n1->keys);
+ const policy_node_keyexpr_t *ct_ka2 = ct_n1->keys;
set_binding_number(&out->bindings, 0, ct_n1->k);
set_binding_keys(&out->bindings, 1, ct_ka2, ct_n1->n);
out->bindings.n = 2;
@@ -260,7 +260,7 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_MULTI_A) break;
const policy_node_multisig_t *ct_n1 = (const policy_node_multisig_t *) leaf_script;
- const policy_node_keyexpr_t *ct_ka2 = r_policy_node_keyexpr(&ct_n1->keys);
+ const policy_node_keyexpr_t *ct_ka2 = ct_n1->keys;
set_binding_number(&out->bindings, 0, ct_n1->k);
set_binding_keys(&out->bindings, 1, ct_ka2, ct_n1->n);
out->bindings.n = 2;
@@ -271,9 +271,9 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_PK) break;
const policy_node_with_key_t *ct_n1 = (const policy_node_with_key_t *) leaf_script;
- const policy_node_keyexpr_t *ct_k2 = r_policy_node_keyexpr(&ct_n1->key);
+ const policy_node_keyexpr_t *ct_k2 = ct_n1->key;
if (ct_k2->type != KEY_EXPRESSION_MUSIG) break;
- const musig_aggr_key_info_t *ct_mi3 = r_musig_aggr_key_info(&ct_k2->m.musig_info);
+ const musig_aggr_key_info_t *ct_mi3 = ct_k2->m.musig_info;
set_binding_number(&out->bindings, 0, ct_mi3->n);
set_binding_keys(&out->bindings, 1, ct_k2, 1);
out->bindings.n = 2;
@@ -285,14 +285,14 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_AND_V) break;
const policy_node_with_script2_t *ct_n1 = (const policy_node_with_script2_t *) leaf_script;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->scripts[0]);
+ const policy_node_t *ct_c2 = ct_n1->scripts[0];
if (ct_c2 == NULL || ct_c2->type != TOKEN_V) break;
const policy_node_with_script_t *ct_w3 = (const policy_node_with_script_t *) ct_c2;
- const policy_node_t *ct_c4 = r_policy_node(&ct_w3->script);
+ const policy_node_t *ct_c4 = ct_w3->script;
ct_leaf_match_t ct_sub5;
if (!match_tapleaf(ct_c4, &ct_sub5)) break;
if (ct_sub5.cls == TC_OTHER || ct_sub5.cls == TC_TIMELOCKED || ct_sub5.cls == TC_AND_V) break;
- const policy_node_t *ct_c6 = r_policy_node(&ct_n1->scripts[1]);
+ const policy_node_t *ct_c6 = ct_n1->scripts[1];
ct_timelock_t ct_tl7;
if (!match_lock_value(ct_c6, &ct_tl7)) break;
set_binding_sub(&out->bindings, 0, ct_c4);
@@ -306,14 +306,14 @@ bool match_tapleaf(const policy_node_t *leaf_script, ct_leaf_match_t *out) {
do {
if (leaf_script == NULL || leaf_script->type != TOKEN_AND_V) break;
const policy_node_with_script2_t *ct_n1 = (const policy_node_with_script2_t *) leaf_script;
- const policy_node_t *ct_c2 = r_policy_node(&ct_n1->scripts[0]);
+ const policy_node_t *ct_c2 = ct_n1->scripts[0];
if (ct_c2 == NULL || ct_c2->type != TOKEN_V) break;
const policy_node_with_script_t *ct_w3 = (const policy_node_with_script_t *) ct_c2;
- const policy_node_t *ct_c4 = r_policy_node(&ct_w3->script);
+ const policy_node_t *ct_c4 = ct_w3->script;
ct_leaf_match_t ct_sub5;
if (!match_tapleaf(ct_c4, &ct_sub5)) break;
if (ct_sub5.cls == TC_OTHER || ct_sub5.cls == TC_TIMELOCKED || ct_sub5.cls == TC_AND_V) break;
- const policy_node_t *ct_c6 = r_policy_node(&ct_n1->scripts[1]);
+ const policy_node_t *ct_c6 = ct_n1->scripts[1];
ct_leaf_match_t ct_sub7;
if (!match_tapleaf(ct_c6, &ct_sub7)) break;
if (ct_sub7.cls == TC_OTHER || ct_sub7.cls == TC_TIMELOCKED || ct_sub7.cls == TC_AND_V) break;
### src/common/wallet.c
@@ -18,6 +18,12 @@
#include "../crypto.h"
+// The key expressions of multi() and friends are allocated one by one, but then accessed as an
+// array through policy_node_multisig_t::keys; that only works if buffer_alloc() lays them out
+// back-to-back, that is, if their size is a multiple of the alignment it pads to.
+_Static_assert(sizeof(policy_node_keyexpr_t) % 4 == 0,
+ "policy_node_keyexpr_t must be a multiple of the buffer_alloc() alignment");
+
typedef struct {
PolicyNodeType type;
const char *name;
@@ -530,9 +536,9 @@ static int parse_keyexpr(buffer_t *in_buf,
memcpy(key_indexes, keys, sizeof(uint16_t) * n_musig_keys);
musig_info->n = n_musig_keys;
- i_uint16(&musig_info->key_indexes, key_indexes);
+ musig_info->key_indexes = key_indexes;
- i_musig_aggr_key_info(&out->m.musig_info, musig_info);
+ out->m.musig_info = musig_info;
} else {
return WITH_ERROR(-1, "Expected key expression starting with '@', or musig");
}
@@ -615,7 +621,7 @@ static int parse_script(buffer_t *in_buf,
static int parse_child_scripts(buffer_t *in_buf,
buffer_t *out_buf,
size_t depth,
- rptr_policy_node_t child_scripts[],
+ policy_node_t *child_scripts[],
int n_children,
int version,
unsigned int context_flags) {
@@ -624,7 +630,7 @@ static int parse_child_scripts(buffer_t *in_buf,
for (int child_index = 0; child_index < n_children; child_index++) {
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node(&child_scripts[child_index], buffer_get_cur(out_buf));
+ child_scripts[child_index] = (policy_node_t *) buffer_get_cur(out_buf);
if (0 > parse_script(in_buf, out_buf, version, depth + 1, context_flags)) {
// failed while parsing internal script
@@ -745,7 +751,7 @@ static int parse_script(buffer_t *in_buf,
}
if (inner_wrapper != NULL) {
- i_policy_node(&inner_wrapper->script, node);
+ inner_wrapper->script = (policy_node_t *) node;
}
inner_wrapper = node;
}
@@ -870,7 +876,7 @@ static int parse_script(buffer_t *in_buf,
// the internal script is recursively parsed (if successful) in the current location
// of the output buffer
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node(&node->script, buffer_get_cur(out_buf));
+ node->script = (policy_node_t *) buffer_get_cur(out_buf);
if (0 > parse_script(in_buf, out_buf, version, depth + 1, inner_context_flags)) {
// failed while parsing internal script
@@ -954,17 +960,17 @@ static int parse_script(buffer_t *in_buf,
}
for (int i = 0; i < 3; i++) {
- if (!r_policy_node(&node->scripts[i])->flags.is_miniscript) {
+ if (!node->scripts[i]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of andor must be miniscript");
}
}
// andor(X, Y, Z)
// X is Bdu; Y and Z are both B, K, or V
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Y = r_policy_node(&node->scripts[1]);
- const policy_node_t *Z = r_policy_node(&node->scripts[2]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Y = node->scripts[1];
+ const policy_node_t *Z = node->scripts[2];
if (X->flags.miniscript_type != MINISCRIPT_TYPE_B || !X->flags.miniscript_mod_d ||
!X->flags.miniscript_mod_u) {
@@ -1017,13 +1023,12 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of and_v must be miniscript");
}
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Y = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Y = node->scripts[1];
// and_v(X,Y)
// X is V; Y is B, K, or V
@@ -1076,13 +1081,12 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of and_b must be miniscript");
}
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Y = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Y = node->scripts[1];
// and_b(X,Y)
// X is B; Y is W
@@ -1132,16 +1136,15 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of and_n must be miniscript");
}
// and_n(X, Y) is equivalent to andor(X, Y, 0)
// X is Bdu; Y is B
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Y = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Y = node->scripts[1];
if (X->flags.miniscript_type != MINISCRIPT_TYPE_B || !X->flags.miniscript_mod_d ||
!X->flags.miniscript_mod_u) {
@@ -1187,16 +1190,15 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of or_b must be miniscript");
}
// or_b(X, Z)
// X is Bd; Z is Wd
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Z = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Z = node->scripts[1];
if (X->flags.miniscript_type != MINISCRIPT_TYPE_B || !X->flags.miniscript_mod_d) {
return WITH_ERROR(-1, "invalid type");
@@ -1243,16 +1245,15 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of or_c must be miniscript");
}
// or_c(X, Z)
// X is Bdu; Z is V
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Z = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Z = node->scripts[1];
if (X->flags.miniscript_type != MINISCRIPT_TYPE_B || !X->flags.miniscript_mod_d ||
!X->flags.miniscript_mod_u) {
@@ -1297,16 +1298,15 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of or_d must be miniscript");
}
// or_d(X, Z)
// X is Bdu; Z is B
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Z = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Z = node->scripts[1];
if (X->flags.miniscript_type != MINISCRIPT_TYPE_B || !X->flags.miniscript_mod_d ||
!X->flags.miniscript_mod_u) {
@@ -1351,16 +1351,15 @@ static int parse_script(buffer_t *in_buf,
return -1;
}
- if (!r_policy_node(&node->scripts[0])->flags.is_miniscript ||
- !r_policy_node(&node->scripts[1])->flags.is_miniscript) {
+ if (!node->scripts[0]->flags.is_miniscript || !node->scripts[1]->flags.is_miniscript) {
return WITH_ERROR(-1, "children of or_i must be miniscript");
}
// or_i(X, Z)
// both are B, K, or V
- const policy_node_t *X = r_policy_node(&node->scripts[0]);
- const policy_node_t *Z = r_policy_node(&node->scripts[1]);
+ const policy_node_t *X = node->scripts[0];
+ const policy_node_t *Z = node->scripts[1];
if (X->flags.miniscript_type == MINISCRIPT_TYPE_W) {
return WITH_ERROR(-1, "invalid type"); // must be B, K or V
@@ -1421,52 +1420,51 @@ static int parse_script(buffer_t *in_buf,
if (scriptlist == NULL) {
return WITH_ERROR(-1, "Out of memory");
}
- i_policy_node_scriptlist(&node->scriptlist, scriptlist);
+ node->scriptlist = scriptlist;
policy_node_scriptlist_t *cur = scriptlist;
- i_policy_node_scriptlist(&cur->next, NULL);
+ cur->next = NULL;
int count_z = 0;
int count_o = 0;
while (true) {
++node->n;
// parse a script into cur->script
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node(&cur->script, buffer_get_cur(out_buf));
+ cur->script = (policy_node_t *) buffer_get_cur(out_buf);
if (0 > parse_script(in_buf, out_buf, version, depth + 1, inner_context_flags)) {
// failed while parsing internal script
return -1;
}
- if (!r_policy_node(&cur->script)->flags.is_miniscript) {
+ if (!cur->script->flags.is_miniscript) {
return WITH_ERROR(-1, "children of thresh must be miniscript");
}
if (node->n == 1) {
// the first child's type must be B
- if (r_policy_node(&cur->script)->flags.miniscript_type != MINISCRIPT_TYPE_B) {
+ if (cur->script->flags.miniscript_type != MINISCRIPT_TYPE_B) {
return WITH_ERROR(-1, "the first children of thresh must be of type B");
}
} else {
// every other child's type must be W
- if (r_policy_node(&cur->script)->flags.miniscript_type != MINISCRIPT_TYPE_W) {
+ if (cur->script->flags.miniscript_type != MINISCRIPT_TYPE_W) {
return WITH_ERROR(
-1,
"each child of thresh (except the first) must be of type W");
}
}
// all children must have properties du
- if (!r_policy_node(&cur->script)->flags.miniscript_mod_d ||
- !r_policy_node(&cur->script)->flags.miniscript_mod_u) {
+ if (!cur->script->flags.miniscript_mod_d || !cur->script->flags.miniscript_mod_u) {
return WITH_ERROR(-1, "each child of thresh must have properties d and u");
}
- if (r_policy_node(&cur->script)->flags.miniscript_mod_z) {
+ if (cur->script->flags.miniscript_mod_z) {
++count_z;
}
- if (r_policy_node(&cur->script)->flags.miniscript_mod_o) {
+ if (cur->script->flags.miniscript_mod_o) {
++count_o;
}
@@ -1480,10 +1478,10 @@ static int parse_script(buffer_t *in_buf,
return WITH_ERROR(-1, "Out of memory");
}
- i_policy_node_scriptlist(&cur->next, next);
+ cur->next = next;
cur = next;
- i_policy_node_scriptlist(&cur->next, NULL);
+ cur->next = NULL;
} else {
// no more scripts to parse
break;
@@ -1528,7 +1526,7 @@ static int parse_script(buffer_t *in_buf,
if (key_expr == NULL) {
return WITH_ERROR(-1, "Out of memory");
}
- i_policy_node_keyexpr(&node->key, key_expr);
+ node->key = key_expr;
if (token == TOKEN_WPKH) {
if (depth > 0 && ((context_flags & CONTEXT_WITHIN_SH) == 0)) {
@@ -1614,7 +1612,7 @@ static int parse_script(buffer_t *in_buf,
if (key_expr == NULL) {
return WITH_ERROR(-1, "Out of memory");
}
- i_policy_node_keyexpr(&node->key, key_expr);
+ node->key = key_expr;
// the taproot internal key can be a musig
if (0 >
@@ -1635,13 +1633,13 @@ static int parse_script(buffer_t *in_buf,
if (0 > parse_tree(in_buf, out_buf, version, depth + 1)) {
return WITH_ERROR(-1, "Failed to parse TREE expression");
}
- i_policy_node_tree(&node->tree, tree);
+ node->tree = tree;
} else {
// no TREE, only tr(KP)
if (c != ')') {
return WITH_ERROR(-1, "Failed to parse tr");
}
- i_policy_node_tree(&node->tree, NULL);
+ node->tree = NULL;
}
parsed_node = (policy_node_t *) node;
@@ -1736,7 +1734,7 @@ static int parse_script(buffer_t *in_buf,
// Note: this is incompatible with musig keys, therefore we don't currently support
// musig nested inside multi_a or sortedmulti_a.
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node_keyexpr(&node->keys, buffer_get_cur(out_buf));
+ node->keys = (policy_node_keyexpr_t *) buffer_get_cur(out_buf);
node->n = 0;
while (true) {
@@ -1819,7 +1817,7 @@ static int parse_script(buffer_t *in_buf,
// if there was one or more wrappers, the script of the most internal node must point
// to the parsed node
if (inner_wrapper != NULL) {
- i_policy_node(&inner_wrapper->script, parsed_node);
+ inner_wrapper->script = parsed_node;
}
// Validate and compute the flags (miniscript type and modifiers) for all the wrapper, if any
@@ -1831,14 +1829,14 @@ static int parse_script(buffer_t *in_buf,
// find the actual node by traversing the list
policy_node_with_script_t *node = (policy_node_with_script_t *) outermost_node;
for (int j = 0; j < i; j++) {
- node = (policy_node_with_script_t *) r_policy_node(&node->script);
+ node = (policy_node_with_script_t *) node->script;
}
- if (!r_policy_node(&node->script)->flags.is_miniscript) {
+ if (!node->script->flags.is_miniscript) {
return WITH_ERROR(-1, "wrappers can only be applied to miniscript");
}
- const policy_node_t *X = r_policy_node(&node->script);
+ const policy_node_t *X = node->script;
uint8_t X_type = X->flags.miniscript_type;
@@ -2025,7 +2023,7 @@ static int parse_tree(buffer_t *in_buf, buffer_t *out_buf, int version, size_t d
tree_node->is_leaf = true;
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node(&tree_node->script, buffer_get_cur(out_buf));
+ tree_node->script = (policy_node_t *) buffer_get_cur(out_buf);
if (0 > parse_script(in_buf, out_buf, version, depth + 1, CONTEXT_WITHIN_TR)) {
return -1;
}
@@ -2036,7 +2034,7 @@ static int parse_tree(buffer_t *in_buf, buffer_t *out_buf, int version, size_t d
// parse first TREE expression
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node_tree(&tree_node->left_tree, buffer_get_cur(out_buf));
+ tree_node->left_tree = (policy_node_tree_t *) buffer_get_cur(out_buf);
if (0 > parse_tree(in_buf, out_buf, version, depth + 1)) {
return -1;
}
@@ -2048,7 +2046,7 @@ static int parse_tree(buffer_t *in_buf, buffer_t *out_buf, int version, size_t d
// parse the second TREE expression
buffer_alloc(out_buf, 0, true); // ensure alignment of current pointer
- i_policy_node_tree(&tree_node->right_tree, buffer_get_cur(out_buf));
+ tree_node->right_tree = (policy_node_tree_t *) buffer_get_cur(out_buf);
if (0 > parse_tree(in_buf, out_buf, version, depth + 1)) {
return -1;
}
@@ -2086,8 +2084,7 @@ int get_policy_segwit_version(const policy_node_t *policy) {
if (policy->type == TOKEN_TR) {
return 1;
} else if (policy->type == TOKEN_SH) {
- const policy_node_t *inner =
- r_policy_node(&((const policy_node_with_script_t *) policy)->script);
+ const policy_node_t *inner = ((const policy_node_with_script_t *) policy)->script;
if (inner->type == TOKEN_WPKH || inner->type == TOKEN_WSH) {
return 0; // wrapped segwit
} else {
@@ -2140,7 +2137,7 @@ __attribute__((noinline)) static int compute_thresh_ops(const policy_node_thresh
if (node->n > MAX_N_IN_THRESH) return -1;
- policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);
+ policy_node_scriptlist_t *cur = node->scriptlist;
out->count = 0;
@@ -2149,7 +2146,7 @@ __attribute__((noinline)) static int compute_thresh_ops(const policy_node_thresh
while (cur != NULL) {
policy_node_ext_info_t t;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&cur->script), &t, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(cur->script, &t, ctx)) return -1;
out->count += t.ops.count + 1;
@@ -2163,7 +2160,7 @@ __attribute__((noinline)) static int compute_thresh_ops(const policy_node_thresh
++sats_size;
memmove(sats, next_sats, sats_size * sizeof(sats[0]));
- cur = r_policy_node_scriptlist(&cur->next);
+ cur = cur->next;
}
out->sat = sats[node->k];
@@ -2179,14 +2176,14 @@ __attribute__((noinline)) static int compute_thresh_stacksize(const policy_node_
if (node->n > MAX_N_IN_THRESH) return -1;
- policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);
+ policy_node_scriptlist_t *cur = node->scriptlist;
sats[0] = 0;
int sats_size = 1;
while (cur != NULL) {
policy_node_ext_info_t t;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&cur->script), &t, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(cur->script, &t, ctx)) return -1;
next_sats[0] = sumcheck(sats[0], t.ss.dsat);
for (int j = 1; j < sats_size; j++) {
@@ -2197,7 +2194,7 @@ __attribute__((noinline)) static int compute_thresh_stacksize(const policy_node_
++sats_size;
memmove(sats, next_sats, sats_size * sizeof(sats[0]));
- cur = r_policy_node_scriptlist(&cur->next);
+ cur = cur->next;
}
out->sat = sats[node->k];
@@ -2381,12 +2378,9 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t y;
policy_node_ext_info_t z;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &y, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[2]), &z, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &y, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[2], &z, ctx)) return -1;
out->s = z.s & (x.s | y.s);
out->f = z.f & (x.s | y.f);
@@ -2421,10 +2415,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t y;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &y, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &y, ctx)) return -1;
out->s = x.s | y.s;
out->f = x.s | y.f;
@@ -2455,10 +2447,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t y;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &y, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &y, ctx)) return -1;
out->s = x.s | y.s;
out->f = (x.f & y.f) | (x.s & x.f) | (y.s & y.f);
@@ -2491,10 +2481,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t y;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &y, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &y, ctx)) return -1;
out->s = x.s | y.s;
out->e = x.s | y.f;
@@ -2524,10 +2512,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t z;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &z, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &z, ctx)) return -1;
out->s = x.s & z.s;
out->e = 1;
@@ -2558,10 +2544,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t z;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &z, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &z, ctx)) return -1;
out->s = x.s & z.s;
out->f = 1;
@@ -2590,10 +2574,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t z;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &z, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &z, ctx)) return -1;
out->s = x.s & z.s;
out->f = z.f;
@@ -2623,10 +2605,8 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
policy_node_ext_info_t x;
policy_node_ext_info_t z;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[0]), &x, ctx))
- return -1;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->scripts[1]), &z, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[0], &x, ctx)) return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->scripts[1], &z, ctx)) return -1;
out->s = x.s & z.s;
out->f = x.f & z.f;
@@ -2655,7 +2635,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
case TOKEN_THRESH: {
const policy_node_thresh_t *node = (const policy_node_thresh_t *) policy_node;
- policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);
+ policy_node_scriptlist_t *cur = node->scriptlist;
int count_s = 0;
int count_e = 0;
@@ -2666,8 +2646,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
++n_children;
policy_node_ext_info_t t;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&cur->script), &t, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(cur->script, &t, ctx)) return -1;
if (t.e) {
++count_e;
@@ -2678,7 +2657,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
if (t.m) {
++count_m;
}
- cur = r_policy_node_scriptlist(&cur->next);
+ cur = cur->next;
out->g |= t.g;
out->h |= t.h;
@@ -2716,8 +2695,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->f = x.f;
@@ -2743,8 +2721,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->f = x.f;
@@ -2771,8 +2748,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = 1;
out->f = x.f;
@@ -2801,8 +2777,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->e = 1;
@@ -2826,8 +2801,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->f = 1;
@@ -2852,8 +2826,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->f = 1;
@@ -2877,8 +2850,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->e = x.f;
@@ -2903,8 +2875,7 @@ int compute_miniscript_policy_ext_info(const policy_node_t *policy_node,
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
policy_node_ext_info_t x;
- if (0 > compute_miniscript_policy_ext_info(r_policy_node(&node->script), &x, ctx))
- return -1;
+ if (0 > compute_miniscript_policy_ext_info(node->script, &x, ctx)) return -1;
out->s = x.s;
out->f = 0;
@@ -2945,15 +2916,11 @@ static int traverse_policy_node_tree(const policy_node_tree_t *tree,
policy_node_callback_t callback,
void *callback_state) {
if (tree->is_leaf) {
- return traverse_policy_dfs(r_policy_node(&tree->script), callback, callback_state);
+ return traverse_policy_dfs(tree->script, callback, callback_state);
} else {
- int ret = traverse_policy_node_tree(r_policy_node_tree(&tree->left_tree),
- callback,
- callback_state);
+ int ret = traverse_policy_node_tree(tree->left_tree, callback, callback_state);
if (ret < 0) return ret;
- return traverse_policy_node_tree(r_policy_node_tree(&tree->right_tree),
- callback,
- callback_state);
+ return traverse_policy_node_tree(tree->right_tree, callback, callback_state);
}
}
@@ -3003,7 +2970,7 @@ int traverse_policy_dfs(const policy_node_t *policy_node,
case TOKEN_L:
case TOKEN_U: {
const policy_node_with_script_t *node = (const policy_node_with_script_t *) policy_node;
- return traverse_policy_dfs(r_policy_node(&node->script), callback, callback_state);
+ return traverse_policy_dfs(node->script, callback, callback_state);
}
// Nodes with exactly two child scripts
@@ -3016,41 +2983,39 @@ int traverse_policy_dfs(const policy_node_t *policy_node,
case TOKEN_OR_I: {
const policy_node_with_script2_t *node =
(const policy_node_with_script2_t *) policy_node;
- ret = traverse_policy_dfs(r_policy_node(&node->scripts[0]), callback, callback_state);
+ ret = traverse_policy_dfs(node->scripts[0], callback, callback_state);
if (ret < 0) return ret;
- return traverse_policy_dfs(r_policy_node(&node->scripts[1]), callback, callback_state);
+ return traverse_policy_dfs(node->scripts[1], callback, callback_state);
}
// Nodes with exactly three child scripts
case TOKEN_ANDOR: {
const policy_node_with_script3_t *node =
(const policy_node_with_script3_t *) policy_node;
- ret = traverse_policy_dfs(r_policy_node(&node->scripts[0]), callback, callback_state);
+ ret = traverse_policy_dfs(node->scripts[0], callback, callback_state);
if (ret < 0) return ret;
- ret = traverse_policy_dfs(r_policy_node(&node->scripts[1]), callback, callback_state);
+ ret = traverse_policy_dfs(node->scripts[1], callback, callback_state);
if (ret < 0) return ret;
- return traverse_policy_dfs(r_policy_node(&node->scripts[2]), callback, callback_state);
+ return traverse_policy_dfs(node->scripts[2], callback, callback_state);
}
// Nodes with a linked list of child scripts
case TOKEN_THRESH: {
const policy_node_thresh_t *node = (const policy_node_thresh_t *) policy_node;
- policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&node->scriptlist);
+ policy_node_scriptlist_t *cur = node->scriptlist;
while (cur != NULL) {
- ret = traverse_policy_dfs(r_policy_node(&cur->script), callback, callback_state);
+ ret = traverse_policy_dfs(cur->script, callback, callback_state);
if (ret < 0) return ret;
- cur = r_policy_node_scriptlist(&cur->next);
+ cur = cur->next;
}
return 0;
}
// tr nodes with a keypath and (possibly) a taptree
case TOKEN_TR: {
const policy_node_tr_t *node = (const policy_node_tr_t *) policy_node;
- if (!isnull_policy_node_tree(&node->tree)) {
- return traverse_policy_node_tree(r_policy_node_tree(&node->tree),
- callback,
- callback_state);
+ if (node->tree != NULL) {
+ return traverse_policy_node_tree(node->tree, callback, callback_state);
}
return 0;
}
### src/common/wallet.h
@@ -52,6 +52,7 @@
// We do not expect these limits to be reached in practice any time soon, but they can
// be further increased if necessary.
#define MAX_DESCRIPTOR_TEMPLATE_LENGTH_V2 512
+
// Memory reserved for the abstract syntax tree of a parsed wallet policy.
// We declare the size based on the size of pointers (which is 4 on the real device),
// so that it doesn't need to be changed when compiling for unit tests.
@@ -196,74 +197,13 @@ typedef enum {
#define MINISCRIPT_TYPE_K 2
#define MINISCRIPT_TYPE_W 3
-// The various structures used to represent the wallet policy abstract syntax tree contain a lot
-// pointers; using a regular pointer would make each of them 4 bytes long, moreover causing
-// additional loss of memory due to padding. Instead, we use a 2-bytes relative pointer to point to
-// policy_nodes, representing a non-negative offset from the position of the structure itself.
-// This reduces the memory utilization of those pointers, and moreover it allows to reduce padding
-// in other structures, as they no longer contain 32-bit pointers.
-// Moreover, avoiding all pointers makes sure that the structure can be copied to a different
-// location if needed (making sure the destination is aligned due to the platform restrictions).
-// The following macro defines the data structure and the helper methods for a relative pointer to a
-// type. The code does not depend on the type, but this allows to keep strong types when dealing
-// with relative pointers, which otherwise would require numerous type casts.
-
-// Defines a relative pointer type for name##t, and the conversion functions to/from a relative
-// pointer and a pointer to name##_t.
-// Relative pointers use an uint16_t to represent the offset; therefore, the offset must be
-// non-negative and at most 65535.
-// An offset of 0 corresponds to a NULL pointer in the conversion (and vice-versa).
-#define DEFINE_REL_PTR(name, type) \
- /* \
- * Relative pointer structure for `type`. \
- * \
- * This structure holds an offset that is used to calculate the actual pointer \
- * to a `type` object. \
- */ \
- typedef struct rptr_##name##_s { \
- uint16_t offset; \
- } rptr_##name##_t; \
- \
- /* \
- * Resolve a relative pointer to a `type` object. \
- * \
- * @param ptr A pointer to the relative pointer structure. \
- * @return A pointer to the `type` object. \
- */ \
- static inline type *r_##name(const rptr_##name##_t *ptr) { \
- if (ptr->offset == 0) \
- return NULL; \
- else \
- return (type *) ((const uint8_t *) ptr + ptr->offset); \
- } \
- \
- /* \
- * Returns true when the offset of the relative pointer is 0 (equivalent to a NULL pointer). \
- * \
- * @param relative_ptr A relative pointer. \
- */ \
- static inline bool isnull_##name(const rptr_##name##_t *ptr) { \
- return ptr->offset == 0; \
- } \
- \
- /* \
- * Initialize a relative pointer to a `type` object. \
- * \
- * @param relative_ptr A pointer to the relative pointer structure to be initialized. \
- * @param obj A pointer to the `type` object. \
- */ \
- static inline void i_##name(rptr_##name##_t *relative_ptr, void *obj) { \
- if (obj == NULL) \
- relative_ptr->offset = 0; \
- else { \
- int offset = (uint8_t *) obj - (uint8_t *) relative_ptr; \
- LEDGER_ASSERT(offset >= 0 && offset < UINT16_MAX, \
- "Relative pointer offset must be in 0-65535 range"); \
- relative_ptr->offset = (uint16_t) offset; \
- } \
- }
-
-// 2 bytes
+// The structures below make up the abstract syntax tree of a wallet policy. They are all
+// bump-allocated inside a single buffer by parse_descriptor_template(), and they refer to each
+// other with plain pointers into that same buffer; therefore, the tree is only valid as long as
+// the buffer it was parsed into is alive, and it cannot be moved elsewhere.
+// The sizes in the comments below are the ones for the 32-bit devices.
+
+// 8 bytes
typedef struct policy_node_s {
PolicyNodeType type;
struct {
@@ -274,11 +214,9 @@ typedef struct policy_node_s {
unsigned int miniscript_mod_n : 1;
unsigned int miniscript_mod_d : 1;
unsigned int miniscript_mod_u : 1;
- } flags; // 1 byte
+ } flags; // 4 bytes
} policy_node_t;
-DEFINE_REL_PTR(policy_node, policy_node_t)
-
typedef struct miniscript_ops_s {
uint16_t count; // non-push opcodes
int16_t sat; // number of keys in possibly executed OP_CHECKMULTISIG(VERIFY)s to satisfy (-1
@@ -314,15 +252,12 @@ typedef struct policy_node_ext_info_s {
unsigned int x : 1; // the last opcode is not EQUAL, CHECKSIG, or CHECKMULTISIG
} policy_node_ext_info_t;
-DEFINE_REL_PTR(uint16, uint16_t)
-
+// 8 bytes
typedef struct {
- uint16_t n; // number of key indexes
- rptr_uint16_t key_indexes; // pointer to an array of exactly n key indexes
+ uint16_t n; // number of key indexes
+ uint16_t *key_indexes; // pointer to an array of exactly n key indexes
} musig_aggr_key_info_t;
-DEFINE_REL_PTR(musig_aggr_key_info, musig_aggr_key_info_t)
-
typedef enum {
KEY_EXPRESSION_NORMAL = 0, // a key expression with a single key expression
KEY_EXPRESSION_MUSIG = 1 // a key expression containing a musig()
@@ -340,7 +275,7 @@ typedef enum {
*/
#pragma GCC diagnostic pop
-// 16 bytes
+// 20 bytes
typedef struct {
// the following fields are only used in V2
uint32_t num_first; // NUM_a of /<NUM_a,NUM_b>/*
@@ -354,78 +289,71 @@ typedef struct {
} k;
// type == 1
struct {
- rptr_musig_aggr_key_info_t musig_info; // only used in V2
+ musig_aggr_key_info_t *musig_info; // only used in V2
} m;
};
uint16_t
keyexpr_index; // index of the key expression in the descriptor template, in parsing order
} policy_node_keyexpr_t;
-DEFINE_REL_PTR(policy_node_keyexpr, policy_node_keyexpr_t)
-
-// 4 bytes
+// 8 bytes
typedef struct {
struct policy_node_s base;
} policy_node_constant_t;
-// 4 bytes
+// 12 bytes
typedef struct {
struct policy_node_s base;
- rptr_policy_node_t script;
+ policy_node_t *script;
} policy_node_with_script_t;
-// 6 bytes
+// 16 bytes
typedef struct {
struct policy_node_s base;
- rptr_policy_node_t scripts[2];
+ policy_node_t *scripts[2];
} policy_node_with_script2_t;
-// 8 bytes
+// 20 bytes
typedef struct {
struct policy_node_s base;
- rptr_policy_node_t scripts[3];
+ policy_node_t *scripts[3];
} policy_node_with_script3_t;
// generic type with pointer for up to 3 (but constant) number of child scripts
typedef policy_node_with_script3_t policy_node_with_scripts_t;
-// 4 bytes
+// 12 bytes
typedef struct {
struct policy_node_s base;
- rptr_policy_node_keyexpr_t key;
+ policy_node_keyexpr_t *key;
} policy_node_with_key_t;
-// 8 bytes
+// 12 bytes
typedef struct {
struct policy_node_s base;
uint32_t n;
} policy_node_with_uint32_t;
-// 12 bytes
+// 16 bytes
typedef struct {
- struct policy_node_s base; // type is TOKEN_MULTI or TOKEN_SORTEDMULTI
- uint16_t k; // threshold
- uint16_t n; // number of keys
- rptr_policy_node_keyexpr_t keys; // pointer to array of exactly n key expressions
+ struct policy_node_s base; // type is TOKEN_MULTI or TOKEN_SORTEDMULTI
+ uint16_t k; // threshold
+ uint16_t n; // number of keys
+ policy_node_keyexpr_t *keys; // pointer to array of exactly n key expressions
} policy_node_multisig_t;
// 8 bytes
-struct policy_node_scriptlist_s; // forward declaration, as the struct is recursive
-
-DEFINE_REL_PTR(policy_node_scriptlist, struct policy_node_scriptlist_s)
-
typedef struct policy_node_scriptlist_s {
- rptr_policy_node_scriptlist_t next;
- rptr_policy_node_t script;
+ struct policy_node_scriptlist_s *next;
+ policy_node_t *script;
} policy_node_scriptlist_t;
-// 12 bytes, (+ 8 bytes for every script)
+// 16 bytes, (+ 8 bytes for every script)
typedef struct {
- struct policy_node_s base; // type is TOKEN_THRESH
- uint16_t k; // threshold
- uint16_t n; // number of child scripts
- rptr_policy_node_scriptlist_t
- scriptlist; // pointer to a linked list of exactly n child scripts
+ struct policy_node_s base; // type is TOKEN_THRESH
+ uint16_t k; // threshold
+ uint16_t n; // number of child scripts
+ policy_node_scriptlist_t *scriptlist; // pointer to a linked list of exactly n child scripts
} policy_node_thresh_t;
typedef struct {
@@ -438,26 +366,25 @@ typedef struct {
uint8_t h[32];
} policy_node_with_hash_256_t;
-struct policy_node_tree_s; // forward declaration, as the struct is recursive
-DEFINE_REL_PTR(policy_node_tree, struct policy_node_tree_s)
-
// a TREE is either a script, or a {TREE,TREE}
+// 12 bytes
typedef struct policy_node_tree_s {
bool is_leaf; // if this is a leaf, then it contains a pointer to a SCRIPT;
// otherwise, it contains two pointers to TREE expressions.
union {
- rptr_policy_node_t script; // pointer to a policy_node_with_script_t
+ policy_node_t *script; // pointer to a policy_node_with_script_t
struct {
- rptr_policy_node_tree_t left_tree; // pointer to a policy_node_tree_s
- rptr_policy_node_tree_t right_tree; // pointer to a policy_node_tree_s
+ struct policy_node_tree_s *left_tree;
+ struct policy_node_tree_s *right_tree;
};
};
} policy_node_tree_t;
+// 16 bytes
typedef struct {
struct policy_node_s base;
- rptr_policy_node_keyexpr_t key;
- rptr_policy_node_tree_t tree; // NULL if tr(KP)
+ policy_node_keyexpr_t *key;
+ policy_node_tree_t *tree; // NULL if tr(KP)
} policy_node_tr_t;
/**
### src/handler/lib/policy.c
@@ -474,8 +474,8 @@ __attribute__((warn_unused_result)) static int get_derived_pubkey(
return -1;
}
} else if (key_expr->type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *musig_info = r_musig_aggr_key_info(&key_expr->m.musig_info);
- const uint16_t *key_indexes = r_uint16(&musig_info->key_indexes);
+ const musig_aggr_key_info_t *musig_info = key_expr->m.musig_info;
+ const uint16_t *key_indexes = musig_info->key_indexes;
plain_pk_t keys[MAX_PUBKEYS_PER_MUSIG];
for (int i = 0; i < musig_info->n; i++) {
// we use ext_pubkey as a temporary variable; will overwrite later
@@ -613,7 +613,7 @@ __attribute__((warn_unused_result)) static int process_generic_node(policy_parse
uint8_t compressed_pubkey[33];
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- r_policy_node_keyexpr(&policy->key),
+ policy->key,
compressed_pubkey)) {
return -1;
}
@@ -634,7 +634,7 @@ __attribute__((warn_unused_result)) static int process_generic_node(policy_parse
uint8_t compressed_pubkey[33];
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- r_policy_node_keyexpr(&policy->key),
+ policy->key,
compressed_pubkey)) {
return -1;
}
@@ -672,16 +672,15 @@ __attribute__((warn_unused_result)) static int process_generic_node(policy_parse
case CMD_CODE_PROCESS_CHILD: {
const policy_node_with_scripts_t *policy =
(const policy_node_with_scripts_t *) node->policy_node;
- if (0 > state_stack_push(state, r_policy_node(&policy->scripts[cmd_data]), 0)) {
+ if (0 > state_stack_push(state, policy->scripts[cmd_data], 0)) {
return -1;
}
break;
}
case CMD_CODE_PROCESS_CHILD_V: {
const policy_node_with_scripts_t *policy =
(const policy_node_with_scripts_t *) node->policy_node;
- if (0 >
- state_stack_push(state, r_policy_node(&policy->scripts[cmd_data]), node->flags)) {
+ if (0 > state_stack_push(state, policy->scripts[cmd_data], node->flags)) {
return -1;
}
break;
@@ -690,7 +689,7 @@ __attribute__((warn_unused_result)) static int process_generic_node(policy_parse
const policy_node_with_scripts_t *policy =
(const policy_node_with_scripts_t *) node->policy_node;
if (0 > state_stack_push(state,
- r_policy_node(&policy->scripts[cmd_data]),
+ policy->scripts[cmd_data],
node->flags | PROCESSOR_FLAG_V)) {
return -1;
}
@@ -720,10 +719,8 @@ __attribute__((warn_unused_result)) static int process_pkh_wpkh_node(policy_pars
uint8_t compressed_pubkey[33];
- if (-1 == get_derived_pubkey(state->dispatcher_context,
- state->wdi,
- r_policy_node_keyexpr(&policy->key),
- compressed_pubkey)) {
+ if (-1 ==
+ get_derived_pubkey(state->dispatcher_context, state->wdi, policy->key, compressed_pubkey)) {
return -1;
} else if (policy->base.type == TOKEN_PKH) {
update_output_u8(state, OP_DUP);
@@ -794,10 +791,10 @@ __attribute__((warn_unused_result)) static int process_thresh_node(policy_parser
if (node->step < policy->n) {
// find the current child node
- policy_node_scriptlist_t *cur = r_policy_node_scriptlist(&policy->scriptlist);
+ policy_node_scriptlist_t *cur = policy->scriptlist;
LEDGER_ASSERT(cur != NULL, "This should never happen");
for (size_t i = 0; i < node->step; i++) {
- cur = r_policy_node_scriptlist(&cur->next);
+ cur = cur->next;
LEDGER_ASSERT(cur != NULL, "This should never happen");
}
@@ -806,7 +803,7 @@ __attribute__((warn_unused_result)) static int process_thresh_node(policy_parser
update_output_u8(state, OP_ADD);
}
- if (-1 == state_stack_push(state, r_policy_node(&cur->script), 0)) {
+ if (-1 == state_stack_push(state, cur->script, 0)) {
return -1;
}
++node->step;
@@ -851,7 +848,7 @@ __attribute__((warn_unused_result)) static int process_multi_sortedmulti_node(
if (policy->base.type == TOKEN_MULTI) {
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- &r_policy_node_keyexpr(&policy->keys)[i],
+ &policy->keys[i],
compressed_pubkey)) {
return -1;
}
@@ -876,7 +873,7 @@ __attribute__((warn_unused_result)) static int process_multi_sortedmulti_node(
uint8_t cur_pubkey[33];
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- &r_policy_node_keyexpr(&policy->keys)[j],
+ &policy->keys[j],
cur_pubkey)) {
return -1;
}
@@ -930,7 +927,7 @@ __attribute__((warn_unused_result)) static int process_multi_a_sortedmulti_a_nod
if (policy->base.type == TOKEN_MULTI_A) {
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- &r_policy_node_keyexpr(&policy->keys)[i],
+ &policy->keys[i],
compressed_pubkey)) {
return -1;
}
@@ -945,7 +942,7 @@ __attribute__((warn_unused_result)) static int process_multi_a_sortedmulti_a_nod
uint8_t cur_pubkey[33];
if (-1 == get_derived_pubkey(state->dispatcher_context,
state->wdi,
- &r_policy_node_keyexpr(&policy->keys)[j],
+ &policy->keys[j],
cur_pubkey)) {
return -1;
}
@@ -1022,9 +1019,8 @@ __attribute__((warn_unused_result, noinline)) static int compute_and_combine_tap
const policy_node_tree_t *tree,
uint8_t out[static 32]) {
uint8_t left_h[32], right_h[32];
- if (0 > compute_taptree_hash(dc, wdi, r_policy_node_tree(&tree->left_tree), left_h)) return -1;
- if (0 > compute_taptree_hash(dc, wdi, r_policy_node_tree(&tree->right_tree), right_h))
- return -1;
+ if (0 > compute_taptree_hash(dc, wdi, tree->left_tree, left_h)) return -1;
+ if (0 > compute_taptree_hash(dc, wdi, tree->right_tree, right_h)) return -1;
crypto_tr_combine_taptree_hashes(left_h, right_h, out);
return 0;
}
@@ -1035,7 +1031,7 @@ __attribute__((noinline)) int compute_taptree_hash(dispatcher_context_t *dc,
const policy_node_tree_t *tree,
uint8_t out[static 32]) {
if (tree->is_leaf)
- return compute_tapleaf_hash(dc, wdi, r_policy_node(&tree->script), out);
+ return compute_tapleaf_hash(dc, wdi, tree->script, out);
else
return compute_and_combine_taptree_child_hashes(dc, wdi, tree, out);
}
@@ -1056,10 +1052,7 @@ int get_wallet_script(dispatcher_context_t *dispatcher_context,
if (policy->type == TOKEN_PKH) {
uint8_t compressed_pubkey[33];
policy_node_with_key_t *pkh_policy = (policy_node_with_key_t *) policy;
- if (0 > get_derived_pubkey(dispatcher_context,
- wdi,
- r_policy_node_keyexpr(&pkh_policy->key),
- compressed_pubkey)) {
+ if (0 > get_derived_pubkey(dispatcher_context, wdi, pkh_policy->key, compressed_pubkey)) {
return -1;
}
out[0] = OP_DUP;
@@ -1075,10 +1068,7 @@ int get_wallet_script(dispatcher_context_t *dispatcher_context,
} else if (policy->type == TOKEN_WPKH) {
uint8_t compressed_pubkey[33];
policy_node_with_key_t *wpkh_policy = (policy_node_with_key_t *) policy;
- if (0 > get_derived_pubkey(dispatcher_context,
- wdi,
- r_policy_node_keyexpr(&wpkh_policy->key),
- compressed_pubkey)) {
+ if (0 > get_derived_pubkey(dispatcher_context, wdi, wpkh_policy->key, compressed_pubkey)) {
return -1;
}
out[0] = OP_0;
@@ -1090,18 +1080,17 @@ int get_wallet_script(dispatcher_context_t *dispatcher_context,
} else if (policy->type == TOKEN_SH || policy->type == TOKEN_WSH) {
const policy_node_t *core_policy;
if (policy->type == TOKEN_SH) {
- const policy_node_t *child =
- r_policy_node(&((const policy_node_with_script_t *) policy)->script);
+ const policy_node_t *child = ((const policy_node_with_script_t *) policy)->script;
if (child->type == TOKEN_WSH) {
script_type = WRAPPED_SCRIPT_TYPE_SH_WSH;
- core_policy = r_policy_node(&((const policy_node_with_script_t *) child)->script);
+ core_policy = ((const policy_node_with_script_t *) child)->script;
} else {
script_type = WRAPPED_SCRIPT_TYPE_SH;
core_policy = child;
}
} else { // if (policy->type == TOKEN_WSH
script_type = WRAPPED_SCRIPT_TYPE_WSH;
- core_policy = r_policy_node(&((const policy_node_with_script_t *) policy)->script);
+ core_policy = ((const policy_node_with_script_t *) policy)->script;
}
if (0 > get_wallet_internal_script_hash(dispatcher_context,
@@ -1154,10 +1143,7 @@ int get_wallet_script(dispatcher_context_t *dispatcher_context,
uint8_t compressed_pubkey[33];
- if (0 > get_derived_pubkey(dispatcher_context,
- wdi,
- r_policy_node_keyexpr(&tr_policy->key),
- compressed_pubkey)) {
+ if (0 > get_derived_pubkey(dispatcher_context, wdi, tr_policy->key, compressed_pubkey)) {
return -1;
}
@@ -1168,11 +1154,8 @@ int get_wallet_script(dispatcher_context_t *dispatcher_context,
uint8_t *h = out + 2; // hack: reuse the output array to save memory
int h_length = 0;
- if (!isnull_policy_node_tree(&tr_policy->tree)) {
- if (0 > compute_taptree_hash(dispatcher_context,
- wdi,
- r_policy_node_tree(&tr_policy->tree),
- h)) {
+ if (tr_policy->tree != NULL) {
+ if (0 > compute_taptree_hash(dispatcher_context, wdi, tr_policy->tree, h)) {
return -1;
}
h_length = 32;
@@ -1388,33 +1371,31 @@ static int get_bip44_purpose(const policy_node_t *descriptor_template) {
int purpose = -1;
switch (descriptor_template->type) {
case TOKEN_PKH:
- kp =
- r_policy_node_keyexpr(&((const policy_node_with_key_t *) descriptor_template)->key);
+ kp = ((const policy_node_with_key_t *) descriptor_template)->key;
purpose = 44; // legacy
break;
case TOKEN_WPKH:
- kp =
- r_policy_node_keyexpr(&((const policy_node_with_key_t *) descriptor_template)->key);
+ kp = ((const policy_node_with_key_t *) descriptor_template)->key;
purpose = 84; // native segwit
break;
case TOKEN_SH: {
const policy_node_t *inner =
- r_policy_node(&((const policy_node_with_script_t *) descriptor_template)->script);
+ ((const policy_node_with_script_t *) descriptor_template)->script;
if (inner->type != TOKEN_WPKH) {
return -1;
}
- kp = r_policy_node_keyexpr(&((const policy_node_with_key_t *) inner)->key);
+ kp = ((const policy_node_with_key_t *) inner)->key;
purpose = 49; // nested segwit
break;
}
case TOKEN_TR: {
const policy_node_tr_t *tr = (const policy_node_tr_t *) descriptor_template;
- if (!isnull_policy_node_tree(&tr->tree)) {
+ if (tr->tree != NULL) {
return -1;
}
- kp = r_policy_node_keyexpr(&((const policy_node_tr_t *) descriptor_template)->key);
+ kp = ((const policy_node_tr_t *) descriptor_template)->key;
purpose = 86; // standard single-key P2TR
break;
}
@@ -1570,21 +1551,18 @@ static int get_keyexpr_by_index_in_tree(const policy_node_tree_t *tree,
const policy_node_t **out_tapleaf_ptr,
policy_node_keyexpr_t **out_keyexpr) {
if (tree->is_leaf) {
- int ret = get_keyexpr_by_index(r_policy_node(&tree->script), i, NULL, out_keyexpr);
+ int ret = get_keyexpr_by_index(tree->script, i, NULL, out_keyexpr);
if (ret >= 0 && out_tapleaf_ptr != NULL && i < (unsigned) ret) {
- *out_tapleaf_ptr = r_policy_node(&tree->script);
+ *out_tapleaf_ptr = tree->script;
}
return ret;
} else {
- int ret1 = get_keyexpr_by_index_in_tree(r_policy_node_tree(&tree->left_tree),
- i,
- out_tapleaf_ptr,
- out_keyexpr);
+ int ret1 = get_keyexpr_by_index_in_tree(tree->left_tree, i, out_tapleaf_ptr, out_keyexpr);
if (ret1 < 0) return -1;
bool found = i < (unsigned int) ret1;
- int ret2 = get_keyexpr_by_index_in_tree(r_policy_node_tree(&tree->right_tree),
+ int ret2 = get_keyexpr_by_index_in_tree(tree->right_tree,
found ? 0 : i - ret1,
found ? NULL : out_tapleaf_ptr,
found ? NULL : out_keyexpr);
@@ -1624,18 +1602,18 @@ int get_keyexpr_by_index(const policy_node_t *policy,
case TOKEN_WPKH: {
if (i == 0) {
policy_node_with_key_t *wpkh = (policy_node_with_key_t *) policy;
- *out_keyexpr = r_policy_node_keyexpr(&wpkh->key);
+ *out_keyexpr = wpkh->key;
}
return 1;
}
case TOKEN_TR: {
policy_node_tr_t *tr = (policy_node_tr_t *) policy;
if (i == 0) {
- *out_keyexpr = r_policy_node_keyexpr(&tr->key);
+ *out_keyexpr = tr->key;
}
- if (!isnull_policy_node_tree(&tr->tree)) {
+ if (tr->tree != NULL) {
int ret_tree = get_keyexpr_by_index_in_tree(
- r_policy_node_tree(&tr->tree),
+ tr->tree,
i == 0 ? 0 : i - 1,
i == 0 ? NULL : out_tapleaf_ptr,
i == 0 ? NULL : out_keyexpr); // if i == 0, we already found it; so we
@@ -1657,7 +1635,7 @@ int get_keyexpr_by_index(const policy_node_t *policy,
const policy_node_multisig_t *node = (const policy_node_multisig_t *) policy;
if (i < (unsigned int) node->n) {
- policy_node_keyexpr_t *key_expressions = r_policy_node_keyexpr(&node->keys);
+ policy_node_keyexpr_t *key_expressions = node->keys;
*out_keyexpr = &key_expressions[i];
}
@@ -1677,11 +1655,10 @@ int get_keyexpr_by_index(const policy_node_t *policy,
case TOKEN_N:
case TOKEN_L:
case TOKEN_U: {
- return get_keyexpr_by_index(
- r_policy_node(&((const policy_node_with_script_t *) policy)->script),
- i,
- out_tapleaf_ptr,
- out_keyexpr);
+ return get_keyexpr_by_index(((const policy_node_with_script_t *) policy)->script,
+ i,
+ out_tapleaf_ptr,
+ out_keyexpr);
}
// nodes with exactly two child scripts
@@ -1693,14 +1670,11 @@ int get_keyexpr_by_index(const policy_node_t *policy,
case TOKEN_OR_D:
case TOKEN_OR_I: {
const policy_node_with_script2_t *node = (const policy_node_with_script2_t *) policy;
- int ret1 = get_keyexpr_by_index(r_policy_node(&node->scripts[0]),
- i,
- out_tapleaf_ptr,
- out_keyexpr);
+ int ret1 = get_keyexpr_by_index(node->scripts[0], i, out_tapleaf_ptr, out_keyexpr);
if (ret1 < 0) return -1;
bool found = i < (unsigned int) ret1;
- int ret2 = get_keyexpr_by_index(r_policy_node(&node->scripts[1]),
+ int ret2 = get_keyexpr_by_index(node->scripts[1],
found ? 0 : i - ret1,
found ? NULL : out_tapleaf_ptr,
found ? NULL : out_keyexpr);
@@ -1712,21 +1686,18 @@ int get_keyexpr_by_index(const policy_node_t *policy,
// nodes with exactly three child scripts
case TOKEN_ANDOR: {
const policy_node_with_script3_t *node = (const policy_node_with_script3_t *) policy;
- int ret1 = get_keyexpr_by_index(r_policy_node(&node->scripts[0]),
- i,
- out_tapleaf_ptr,
- out_keyexpr);
+ int ret1 = get_keyexpr_by_index(node->scripts[0], i, out_tapleaf_ptr, out_keyexpr);
if (ret1 < 0) return -1;
bool found = i < (unsigned int) ret1;
- int ret2 = get_keyexpr_by_index(r_policy_node(&node->scripts[1]),
+ int ret2 = get_keyexpr_by_index(node->scripts[1],
found ? 0 : i - ret1,
found ? NULL : out_tapleaf_ptr,
found ? NULL : out_keyexpr);
if (ret2 < 0) return -1;
found = i < (unsigned int) (ret1 + ret2);
- int ret3 = get_keyexpr_by_index(r_policy_node(&node->scripts[2]),
+ int ret3 = get_keyexpr_by_index(node->scripts[2],
found ? 0 : i - ret1 - ret2,
found ? NULL : out_tapleaf_ptr,
found ? NULL : out_keyexpr);
@@ -1739,19 +1710,19 @@ int get_keyexpr_by_index(const policy_node_t *policy,
const policy_node_thresh_t *node = (const policy_node_thresh_t *) policy;
bool found;
int ret = 0;
- policy_node_scriptlist_t *cur_child = r_policy_node_scriptlist(&node->scriptlist);
+ policy_node_scriptlist_t *cur_child = node->scriptlist;
for (int script_idx = 0; script_idx < node->n; script_idx++) {
LEDGER_ASSERT(cur_child != NULL, "The script must have exactly n child scripts");
found = i < (unsigned int) ret;
- int ret_partial = get_keyexpr_by_index(r_policy_node(&cur_child->script),
+ int ret_partial = get_keyexpr_by_index(cur_child->script,
found ? 0 : i - ret,
found ? NULL : out_tapleaf_ptr,
found ? NULL : out_keyexpr);
if (ret_partial < 0) return -1;
ret += ret_partial;
- cur_child = r_policy_node_scriptlist(&cur_child->next);
+ cur_child = cur_child->next;
}
return ret;
}
@@ -1782,9 +1753,8 @@ int count_distinct_keys_info(const policy_node_t *policy) {
if (key_expression_ptr->type == KEY_EXPRESSION_NORMAL) {
ret = MAX(ret, key_expression_ptr->k.key_index + 1);
} else if (key_expression_ptr->type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *musig_info =
- r_musig_aggr_key_info(&key_expression_ptr->m.musig_info);
- const uint16_t *key_indexes = r_uint16(&musig_info->key_indexes);
+ const musig_aggr_key_info_t *musig_info = key_expression_ptr->m.musig_info;
+ const uint16_t *key_indexes = musig_info->key_indexes;
for (int i = 0; i < musig_info->n; i++) {
ret = MAX(ret, key_indexes[i] + 1);
}
@@ -1890,16 +1860,16 @@ static int is_taptree_miniscript_sane(const policy_node_tree_t *taptree) {
// Recurse until leaves are found, then check sanity if they contain miniscript.
// No check is performed on leaves not containing miniscript.
if (taptree->is_leaf) {
- const policy_node_t *script = r_policy_node(&taptree->script);
+ const policy_node_t *script = taptree->script;
if (script->flags.is_miniscript && // only check for miniscript leaves
0 > is_miniscript_sane(script, MINISCRIPT_CONTEXT_TAPSCRIPT)) {
return -1;
}
} else {
- if (0 > is_taptree_miniscript_sane(r_policy_node_tree(&taptree->left_tree))) {
+ if (0 > is_taptree_miniscript_sane(taptree->left_tree)) {
return -1;
}
- if (0 > is_taptree_miniscript_sane(r_policy_node_tree(&taptree->right_tree))) {
+ if (0 > is_taptree_miniscript_sane(taptree->right_tree)) {
return -1;
}
}
@@ -1922,10 +1892,10 @@ bool are_key_placeholders_identical(const policy_node_keyexpr_t *kp1,
if (kp1->type == KEY_EXPRESSION_NORMAL && kp2->type == KEY_EXPRESSION_NORMAL) {
return kp1->k.key_index == kp2->k.key_index;
} else if (kp1->type == KEY_EXPRESSION_MUSIG && kp2->type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *musig_info_i = r_musig_aggr_key_info(&kp1->m.musig_info);
- const uint16_t *key_indexes_i = r_uint16(&musig_info_i->key_indexes);
- const musig_aggr_key_info_t *musig_info_j = r_musig_aggr_key_info(&kp2->m.musig_info);
- const uint16_t *key_indexes_j = r_uint16(&musig_info_j->key_indexes);
+ const musig_aggr_key_info_t *musig_info_i = kp1->m.musig_info;
+ const uint16_t *key_indexes_i = musig_info_i->key_indexes;
+ const musig_aggr_key_info_t *musig_info_j = kp2->m.musig_info;
+ const uint16_t *key_indexes_j = musig_info_j->key_indexes;
// two musig key expressions have identical placeholders if and only if they have
// exactly the same set of key indexes
@@ -1978,8 +1948,7 @@ int is_policy_sane(dispatcher_context_t *dispatcher_context,
const uint8_t keys_merkle_root[static 32],
uint32_t n_keys) {
if (policy->type == TOKEN_WSH) {
- const policy_node_t *inner =
- r_policy_node(&((const policy_node_with_script_t *) policy)->script);
+ const policy_node_t *inner = ((const policy_node_with_script_t *) policy)->script;
if (inner->flags.is_miniscript) {
if (0 > is_miniscript_sane(inner, MINISCRIPT_CONTEXT_P2WSH)) {
return -1;
@@ -1988,7 +1957,7 @@ int is_policy_sane(dispatcher_context_t *dispatcher_context,
} else if (policy->type == TOKEN_TR) {
// if there is a taptree, we check the sanity of every miniscript leaf
const policy_node_tr_t *tr = (const policy_node_tr_t *) policy;
- const policy_node_tree_t *taptree = r_policy_node_tree(&tr->tree);
+ const policy_node_tree_t *taptree = tr->tree;
if (taptree != NULL && 0 > is_taptree_miniscript_sane(taptree)) {
return -1;
}
@@ -2048,8 +2017,8 @@ int is_policy_sane(dispatcher_context_t *dispatcher_context,
return WITH_ERROR(-1, "Unexpected error retrieving key expressions from the policy");
}
if (kp_i->type == KEY_EXPRESSION_MUSIG) {
- const musig_aggr_key_info_t *musig_info_i = r_musig_aggr_key_info(&kp_i->m.musig_info);
- const uint16_t *key_indexes_i = r_uint16(&musig_info_i->key_indexes);
+ const musig_aggr_key_info_t *musig_info_i = kp_i->m.musig_info;
+ const uint16_t *key_indexes_i = musig_info_i->key_indexes;
uint16_t key_indexes_i_sorted[MAX_PUBKEYS_PER_MUSIG];
memcpy(key_indexes_i_sorted, key_indexes_i, musig_info_i->n * sizeof(uint16_t));
### src/handler/sign_psbt/init_global_state.c
@@ -330,9 +330,8 @@ bool fill_keyexpr_info_if_internal(dispatcher_context_t *dc,
return result;
} else if (keyexpr_info->key_expression_ptr->type == KEY_EXPRESSION_MUSIG) {
// iterate through the keys of the musig() placeholder to find if a key is internal
- const musig_aggr_key_info_t *musig_info =
- r_musig_aggr_key_info(&keyexpr_info->key_expression_ptr->m.musig_info);
- const uint16_t *key_indexes = r_uint16(&musig_info->key_indexes);
+ const musig_aggr_key_info_t *musig_info = keyexpr_info->key_expression_ptr->m.musig_info;
+ const uint16_t *key_indexes = musig_info->key_indexes;
bool has_internal_key = false;
### src/handler/sign_psbt/musig_signing.c
@@ -62,8 +62,8 @@ bool compute_musig_per_input_info(dispatcher_context_t *dc,
serialized_extended_pubkey_t ext_pubkey;
const policy_node_keyexpr_t *key_expr = keyexpr_info->key_expression_ptr;
- const musig_aggr_key_info_t *musig_info = r_musig_aggr_key_info(&key_expr->m.musig_info);
- const uint16_t *key_indexes = r_uint16(&musig_info->key_indexes);
+ const musig_aggr_key_info_t *musig_info = key_expr->m.musig_info;
+ const uint16_t *key_indexes = musig_info->key_indexes;
LEDGER_ASSERT(musig_info->n <= MAX_PUBKEYS_PER_MUSIG, "Too many keys in musig key expression");
for (int i = 0; i < musig_info->n; i++) {
@@ -121,15 +121,15 @@ bool compute_musig_per_input_info(dispatcher_context_t *dc,
32,
input->taptree_hash,
// BIP-86 compliant tweak if there's no taptree, otherwise use the taptree hash
- isnull_policy_node_tree(&tr_policy->tree) ? 0 : 32,
+ tr_policy->tree == NULL ? 0 : 32,
out->tweaks[2]);
// also apply the taptweak to agg_key_tweaked
uint8_t parity = 0;
crypto_tr_tweak_pubkey(out->agg_key_tweaked.compressed_pubkey + 1,
input->taptree_hash,
- isnull_policy_node_tree(&tr_policy->tree) ? 0 : 32,
+ tr_policy->tree == NULL ? 0 : 32,
&parity,
out->agg_key_tweaked.compressed_pubkey + 1);
out->agg_key_tweaked.compressed_pubkey[0] = 0x02 + parity;
@@ -399,7 +399,7 @@ bool __attribute__((noinline)) sign_sighash_musig_and_yield(dispatcher_context_t
// collect all pubnonces
const policy_node_keyexpr_t *key_expr = keyexpr_info->key_expression_ptr;
- const musig_aggr_key_info_t *musig_info = r_musig_aggr_key_info(&key_expr->m.musig_info);
+ const musig_aggr_key_info_t *musig_info = key_expr->m.musig_info;
musig_pubnonce_t nonces[MAX_PUBKEYS_PER_MUSIG];
### src/handler/sign_psbt/sign_input.c
@@ -400,7 +400,7 @@ static bool __attribute__((noinline)) sign_transaction_input(dispatcher_context_
return false;
policy_node_tr_t *policy = (policy_node_tr_t *) st->account.policy_map;
- if (!keyexpr_info->is_tapscript && !isnull_policy_node_tree(&policy->tree)) {
+ if (!keyexpr_info->is_tapscript && policy->tree != NULL) {
// keypath spend, we compute the taptree hash
if (0 > compute_taptree_hash(
dc,
@@ -411,7 +411,7 @@ static bool __attribute__((noinline)) sign_transaction_input(dispatcher_context_
.n_keys = st->account.wallet_header.n_keys,
.wallet_version = st->account.wallet_header.version,
.sign_psbt_cache = sign_psbt_cache},
- r_policy_node_tree(&policy->tree),
+ policy->tree,
input->taptree_hash)) {
PRINTF("Error while computing taptree hash\n");
SEND_SW(dc, SW_BAD_STATE);
@@ -424,7 +424,7 @@ static bool __attribute__((noinline)) sign_transaction_input(dispatcher_context_
const uint8_t *tapleaf_hash = NULL;
if (!keyexpr_info->is_tapscript) {
// keypath spend
- if (isnull_policy_node_tree(&policy->tree)) {
+ if (policy->tree == NULL) {
// tweak as specified in BIP-86 and BIP-386
tweak_data = (uint8_t[]) {};
tweak_data_len = 0;
@@ -600,7 +600,7 @@ bool __attribute__((noinline)) produce_musig2_pubnonces(
// an internal key), and might not be needed at all otherwise. Therefore, it is
// actually more efficient to compute it here.
policy_node_tr_t *policy = (policy_node_tr_t *) st->account.policy_map;
- bool has_taptree = !isnull_policy_node_tree(&policy->tree);
+ bool has_taptree = policy->tree != NULL;
if (has_taptree) {
if (0 >
compute_taptree_hash(
@@ -612,7 +612,7 @@ bool __attribute__((noinline)) produce_musig2_pubnonces(
.n_keys = st->account.wallet_header.n_keys,
.wallet_version = st->account.wallet_header.version,
.sign_psbt_cache = sign_psbt_cache},
- r_policy_node_tree(&policy->tree),
+ policy->tree,
input.taptree_hash)) {
PRINTF("Error while computing taptree hash\n");
SEND_SW(dc, SW_BAD_STATE);
### unit-tests/test_wallet.c
@@ -41,9 +41,9 @@ static void check_key_expr_musig(const policy_node_keyexpr_t *ptr,
uint32_t num_first,
uint32_t num_second) {
assert_int_equal(ptr->type, KEY_EXPRESSION_MUSIG);
- musig_aggr_key_info_t *musig_info = r_musig_aggr_key_info(&ptr->m.musig_info);
+ musig_aggr_key_info_t *musig_info = ptr->m.musig_info;
assert_int_equal(musig_info->n, n_musig_keys);
- uint16_t *musig_key_indexes = r_uint16(&musig_info->key_indexes);
+ uint16_t *musig_key_indexes = musig_info->key_indexes;
for (int i = 0; i < n_musig_keys; i++) {
assert_int_equal(musig_key_indexes[i], key_indices[i]);
}
@@ -62,7 +62,7 @@ static void test_parse_policy_map_singlesig_1(void **state) {
policy_node_with_key_t *node_1 = (policy_node_with_key_t *) out;
assert_int_equal(node_1->base.type, TOKEN_PKH);
- check_key_expr_plain(r_policy_node_keyexpr(&node_1->key), 0, 0, 1);
+ check_key_expr_plain(node_1->key, 0, 0, 1);
}
static void test_parse_policy_map_singlesig_2(void **state) {
@@ -77,10 +77,10 @@ static void test_parse_policy_map_singlesig_2(void **state) {
assert_int_equal(root->base.type, TOKEN_SH);
- policy_node_with_key_t *inner = (policy_node_with_key_t *) r_policy_node(&root->script);
+ policy_node_with_key_t *inner = (policy_node_with_key_t *) root->script;
assert_int_equal(inner->base.type, TOKEN_WPKH);
- check_key_expr_plain(r_policy_node_keyexpr(&inner->key), 0, 0, 1);
+ check_key_expr_plain(inner->key, 0, 0, 1);
}
static void test_parse_policy_map_singlesig_3(void **state) {
@@ -95,14 +95,14 @@ static void test_parse_policy_map_singlesig_3(void **state) {
assert_int_equal(root->base.type, TOKEN_SH);
- policy_node_with_script_t *mid = (policy_node_with_script_t *) r_policy_node(&root->script);
+ policy_node_with_script_t *mid = (policy_node_with_script_t *) root->script;
assert_int_equal(mid->base.type, TOKEN_WSH);
- policy_node_with_key_t *inner = (policy_node_with_key_t *) r_policy_node(&mid->script);
+ policy_node_with_key_t *inner = (policy_node_with_key_t *) mid->script;
assert_int_equal(inner->base.type, TOKEN_PKH);
- check_key_expr_plain(r_policy_node_keyexpr(&inner->key), 0, 0, 1);
+ check_key_expr_plain(inner->key, 0, 0, 1);
}
static void test_parse_policy_map_multisig_1(void **state) {
@@ -118,9 +118,9 @@ static void test_parse_policy_map_multisig_1(void **state) {
assert_int_equal(node_1->base.type, TOKEN_SORTEDMULTI);
assert_int_equal(node_1->k, 2);
assert_int_equal(node_1->n, 3);
- check_key_expr_plain(&r_policy_node_keyexpr(&node_1->keys)[0], 0, 0, 1);
- check_key_expr_plain(&r_policy_node_keyexpr(&node_1->keys)[1], 1, 0, 1);
- check_key_expr_plain(&r_policy_node_keyexpr(&node_1->keys)[2], 2, 0, 1);
+ check_key_expr_plain(&node_1->keys[0], 0, 0, 1);
+ check_key_expr_plain(&node_1->keys[1], 1, 0, 1);
+ check_key_expr_plain(&node_1->keys[2], 2, 0, 1);
}
static void test_parse_policy_map_multisig_2(void **state) {
@@ -135,13 +135,13 @@ static void test_parse_policy_map_multisig_2(void **state) {
assert_int_equal(root->base.type, TOKEN_WSH);
- policy_node_multisig_t *inner = (policy_node_multisig_t *) r_policy_node(&root->script);
+ policy_node_multisig_t *inner = (policy_node_multisig_t *) root->script;
assert_int_equal(inner->base.type, TOKEN_MULTI);
assert_int_equal(inner->k, 3);
assert_int_equal(inner->n, 5);
for (int i = 0; i < 5; i++) {
- check_key_expr_plain(&r_policy_node_keyexpr(&inner->keys)[i], i, 0, 1);
+ check_key_expr_plain(&inner->keys[i], i, 0, 1);
}
}
@@ -158,16 +158,16 @@ static void test_parse_policy_map_multisig_3(void **state) {
assert_int_equal(root->base.type, TOKEN_SH);
- policy_node_with_script_t *mid = (policy_node_with_script_t *) r_policy_node(&root->script);
+ policy_node_with_script_t *mid = (policy_node_with_script_t *) root->script;
assert_int_equal(mid->base.type, TOKEN_WSH);
- policy_node_multisig_t *inner = (policy_node_multisig_t *) r_policy_node(&mid->script);
+ policy_node_multisig_t *inner = (policy_node_multisig_t *) mid->script;
assert_int_equal(inner->base.type, TOKEN_SORTEDMULTI);
assert_int_equal(inner->k, 3);
assert_int_equal(inner->n, 5);
for (int i = 0; i < 5; i++) {
- check_key_expr_plain(&r_policy_node_keyexpr(&inner->keys)[i], i, 0, 1);
+ check_key_expr_plain(&inner->keys[i], i, 0, 1);
}
}
@@ -183,54 +183,49 @@ static void test_parse_policy_tr(void **state) {
assert_true(res >= 0);
policy_node_tr_t *root = (policy_node_tr_t *) out;
- assert_true(isnull_policy_node_tree(&root->tree));
- check_key_expr_plain(r_policy_node_keyexpr(&root->key), 0, 0, 1);
+ assert_true(root->tree == NULL);
+ check_key_expr_plain(root->key, 0, 0, 1);
// Simple tr with a TREE that is a simple script
res = parse_policy("tr(@0/**,pk(@1/**))", out, sizeof(out));
assert_true(res >= 0);
root = (policy_node_tr_t *) out;
- check_key_expr_plain(r_policy_node_keyexpr(&root->key), 0, 0, 1);
+ check_key_expr_plain(root->key, 0, 0, 1);
- assert_int_equal(r_policy_node_tree(&root->tree)->is_leaf, true);
+ assert_int_equal(root->tree->is_leaf, true);
- policy_node_with_key_t *tapscript =
- (policy_node_with_key_t *) r_policy_node(&r_policy_node_tree(&root->tree)->script);
+ policy_node_with_key_t *tapscript = (policy_node_with_key_t *) root->tree->script;
assert_int_equal(tapscript->base.type, TOKEN_PK);
- check_key_expr_plain(r_policy_node_keyexpr(&tapscript->key), 1, 0, 1);
+ check_key_expr_plain(tapscript->key, 1, 0, 1);
// Simple tr with a TREE with two tapleaves
res = parse_policy("tr(@0/**,{pk(@1/**),pk(@2/<5;7>/*)})", out, sizeof(out));
assert_true(res >= 0);
root = (policy_node_tr_t *) out;
- check_key_expr_plain(r_policy_node_keyexpr(&root->key), 0, 0, 1);
+ check_key_expr_plain(root->key, 0, 0, 1);
- policy_node_tree_t *taptree = r_policy_node_tree(&root->tree);
+ policy_node_tree_t *taptree = root->tree;
assert_int_equal(taptree->is_leaf, false);
- policy_node_tree_t *taptree_left =
- (policy_node_tree_t *) r_policy_node_tree(&taptree->left_tree);
+ policy_node_tree_t *taptree_left = (policy_node_tree_t *) taptree->left_tree;
assert_int_equal(taptree_left->is_leaf, true);
- policy_node_with_key_t *tapscript_left =
- (policy_node_with_key_t *) r_policy_node(&taptree_left->script);
+ policy_node_with_key_t *tapscript_left = (policy_node_with_key_t *) taptree_left->script;
assert_int_equal(tapscript_left->base.type, TOKEN_PK);
- check_key_expr_plain(r_policy_node_keyexpr(&tapscript_left->key), 1, 0, 1);
+ check_key_expr_plain(tapscript_left->key, 1, 0, 1);
- policy_node_tree_t *taptree_right =
- (policy_node_tree_t *) r_policy_node_tree(&taptree->right_tree);
+ policy_node_tree_t *taptree_right = (policy_node_tree_t *) taptree->right_tree;
assert_int_equal(taptree_right->is_leaf, true);
- policy_node_with_key_t *tapscript_right =
- (policy_node_with_key_t *) r_policy_node(&taptree_right->script);
+ policy_node_with_key_t *tapscript_right = (policy_node_with_key_t *) taptree_right->script;
assert_int_equal(tapscript_right->base.type, TOKEN_PK);
- check_key_expr_plain(r_policy_node_keyexpr(&tapscript_right->key), 2, 5, 7);
+ check_key_expr_plain(tapscript_right->key, 2, 5, 7);
}
static void test_parse_policy_tr_multisig(void **state) {
@@ -248,38 +243,34 @@ static void test_parse_policy_tr_multisig(void **state) {
policy_node_tr_t *root = (policy_node_tr_t *) out;
- assert_int_equal(r_policy_node_keyexpr(&root->key)->k.key_index, 0);
- assert_int_equal(r_policy_node_keyexpr(&root->key)->num_first, 0);
- assert_int_equal(r_policy_node_keyexpr(&root->key)->num_second, 1);
+ assert_int_equal(root->key->k.key_index, 0);
+ assert_int_equal(root->key->num_first, 0);
+ assert_int_equal(root->key->num_second, 1);
- policy_node_tree_t *taptree = r_policy_node_tree(&root->tree);
+ policy_node_tree_t *taptree = root->tree;
assert_int_equal(taptree->is_leaf, false);
- policy_node_tree_t *taptree_left =
- (policy_node_tree_t *) r_policy_node_tree(&taptree->left_tree);
+ policy_node_tree_t *taptree_left = (policy_node_tree_t *) taptree->left_tree;
assert_int_equal(taptree_left->is_leaf, true);
- policy_node_multisig_t *tapscript_left =
- (policy_node_multisig_t *) r_policy_node(&taptree_left->script);
+ policy_node_multisig_t *tapscript_left = (policy_node_multisig_t *) taptree_left->script;
assert_int_equal(tapscript_left->base.type, TOKEN_MULTI_A);
assert_int_equal(tapscript_left->k, 1);
assert_int_equal(tapscript_left->n, 2);
- check_key_expr_plain(&r_policy_node_keyexpr(&tapscript_left->keys)[0], 1, 0, 1);
- check_key_expr_plain(&r_policy_node_keyexpr(&tapscript_left->keys)[1], 2, 0, 1);
+ check_key_expr_plain(&tapscript_left->keys[0], 1, 0, 1);
+ check_key_expr_plain(&tapscript_left->keys[1], 2, 0, 1);
- policy_node_tree_t *taptree_right =
- (policy_node_tree_t *) r_policy_node_tree(&taptree->right_tree);
+ policy_node_tree_t *taptree_right = (policy_node_tree_t *) taptree->right_tree;
assert_int_equal(taptree_right->is_leaf, true);
- policy_node_multisig_t *tapscript_right =
- (policy_node_multisig_t *) r_policy_node(&taptree_right->script);
+ policy_node_multisig_t *tapscript_right = (policy_node_multisig_t *) taptree_right->script;
assert_int_equal(tapscript_right->base.type, TOKEN_SORTEDMULTI_A);
assert_int_equal(tapscript_right->k, 2);
assert_int_equal(tapscript_right->n, 3);
- check_key_expr_plain(&r_policy_node_keyexpr(&tapscript_right->keys)[0], 3, 0, 1);
- check_key_expr_plain(&r_policy_node_keyexpr(&tapscript_right->keys)[1], 4, 0, 1);
- check_key_expr_plain(&r_policy_node_keyexpr(&tapscript_right->keys)[2], 5, 0, 1);
+ check_key_expr_plain(&tapscript_right->keys[0], 3, 0, 1);
+ check_key_expr_plain(&tapscript_right->keys[1], 4, 0, 1);
+ check_key_expr_plain(&tapscript_right->keys[2], 5, 0, 1);
}
static void test_parse_policy_tr_musig_keypath(void **state) {
@@ -294,9 +285,9 @@ static void test_parse_policy_tr_musig_keypath(void **state) {
policy_node_tr_t *root = (policy_node_tr_t *) out;
assert_int_equal(root->base.type, TOKEN_TR);
- assert_true(isnull_policy_node_tree(&root->tree));
+ assert_true(root->tree == NULL);
- check_key_expr_musig(r_policy_node_keyexpr(&root->key), 3, (uint16_t[]) {2, 0, 1}, 3, 13);
+ check_key_expr_musig(root->key, 3, (uint16_t[]) {2, 0, 1}, 3, 13);
}
static void test_parse_policy_tr_musig_scriptpath(void **state) {
@@ -313,14 +304,14 @@ static void test_parse_policy_tr_musig_scriptpath(void **state) {
policy_node_tr_t *root = (policy_node_tr_t *) out;
assert_int_equal(root->base.type, TOKEN_TR);
- assert_false(isnull_policy_node_tree(&root->tree));
- policy_node_tree_t *tree = r_policy_node_tree(&root->tree);
+ assert_false(root->tree == NULL);
+ policy_node_tree_t *tree = root->tree;
assert_true(tree->is_leaf);
- policy_node_with_key_t *script_pk = (policy_node_with_key_t *) r_policy_node(&tree->script);
+ policy_node_with_key_t *script_pk = (policy_node_with_key_t *) tree->script;
assert_int_equal(script_pk->base.type, TOKEN_PK);
- check_key_expr_musig(r_policy_node_keyexpr(&script_pk->key), 3, (uint16_t[]) {2, 0, 3}, 0, 1);
+ check_key_expr_musig(script_pk->key, 3, (uint16_t[]) {2, 0, 3}, 0, 1);
}
static void test_get_policy_segwit_version(void **state) {
@@ -546,14 +537,14 @@ static void Test(const char *ms, const char *hexscript, int mode, int opslimit,
const policy_node_t *miniscript;
int context;
if (((policy_node_t *) out)->type == TOKEN_WSH) {
- miniscript = r_policy_node(&((policy_node_with_script_t *) out)->script);
+ miniscript = ((policy_node_with_script_t *) out)->script;
context = MINISCRIPT_CONTEXT_P2WSH;
} else {
assert_true(((policy_node_t *) out)->type == TOKEN_TR);
policy_node_tr_t *tr = (policy_node_tr_t *) out;
- assert_true(r_policy_node_tree(&tr->tree)->is_leaf);
+ assert_true(tr->tree->is_leaf);
- miniscript = r_policy_node(&r_policy_node_tree(&tr->tree)->script);
+ miniscript = tr->tree->script;
context = MINISCRIPT_CONTEXT_TAPSCRIPT;
}
@@ -961,7 +952,7 @@ static void test_parse_policy_max_depth_wrappers(void **state) {
make_wrapper_chain(policy, sizeof(policy), n_wrappers);
assert_true(0 <= parse_policy(policy, out, sizeof(out)));
- const policy_node_t *inner = r_policy_node(&((policy_node_with_script_t *) out)->script);
+ const policy_node_t *inner = ((policy_node_with_script_t *) out)->script;
policy_node_ext_info_t ext_info;
assert_int_equal(compute_miniscript_policy_ext_info(inner, &ext_info, MINISCRIPT_CONTEXT_P2WSH),
0);
@@ -989,7 +980,7 @@ static void test_parse_policy_max_thresh_nesting(void **state) {
assert_true(0 <= parse_policy(policy, out, sizeof(out)));
// the deepest accepted nesting must also be processed by the recursive walkers
- const policy_node_t *inner = r_policy_node(&((policy_node_with_script_t *) out)->script);
+ const policy_node_t *inner = ((policy_node_with_script_t *) out)->script;
policy_node_ext_info_t ext_info;
assert_int_equal(compute_miniscript_policy_ext_info(inner, &ext_info, MINISCRIPT_CONTEXT_P2WSH),
0);
@@ -1027,13 +1018,13 @@ static void test_max_n_in_thresh(void **state) {
make_wide_thresh(policy, sizeof(policy), MAX_N_IN_THRESH);
assert_true(0 <= parse_policy(policy, out, sizeof(out)));
- const policy_node_t *inner = r_policy_node(&((policy_node_with_script_t *) out)->script);
+ const policy_node_t *inner = ((policy_node_with_script_t *) out)->script;
assert_int_equal(compute_miniscript_policy_ext_info(inner, &ext_info, MINISCRIPT_CONTEXT_P2WSH),
0);
make_wide_thresh(policy, sizeof(policy), MAX_N_IN_THRESH + 1);
assert_true(0 <= parse_policy(policy, out, sizeof(out)));
- inner = r_policy_node(&((policy_node_with_script_t *) out)->script);
+ inner = ((policy_node_with_script_t *) out)->script;
assert_true(0 > compute_miniscript_policy_ext_info(inner, &ext_info, MINISCRIPT_CONTEXT_P2WSH));
}
Why this scored 30/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.