Merge pull request #546 from LedgerHQ/simplify_ast
What changed, and why it matters
This commit is a large internal refactoring of the Ledger Bitcoin app's wallet-policy parser. It replaces compact 'relative pointers' with ordinary memory pointers in the abstract syntax tree (AST) used to represent Bitcoin wallet descriptors. The change increases the memory each policy node uses, so the app also enlarges the policy buffer and updates related size limits. There is no direct evidence in the commit that this fixes an exploitable vulnerability; it appears to be a code-simplification and maintainability change. However, because it touches memory layout and parsing limits, it could indirectly affect security if the old relative-pointer scheme had subtle bugs or if the new buffer sizing introduces edge cases.
Treat this as a routine but high-touch refactoring. Review that the new pointer-based AST cannot be moved/copied (the commit notes this explicitly), and verify that all callers respect the lifetime of the underlying buffer. Re-run the existing test suite, especially deep-wrapper-chain and large-policy tests, on real device builds to confirm the increased buffer sizes do not cause RAM exhaustion on Nano X. No immediate security patch is indicated, but monitor for follow-up fixes that might reveal a latent bug in the old relative-pointer code.
Security signals we found
Large-scale memory-layout refactoring of security-critical parser
Removal of custom relative-pointer abstraction, eliminating a class of offset-calculation bugs
Increase in policy buffer size limits and key-info length limits
Addition of alignment static assertion for contiguous key-expression allocation
No explicit security bug fix or vulnerability disclosure in commit message or diff
Evidence from the diff
The commit removes the DEFINE_REL_PTR macro and all rptr_/r_/i_/isnull_ helpers, converting AST structures (policy_node_with_script_t, policy_node_with_key_t, policy_node_multisig_t, policy_node_scriptlist_t, policy_node_tree_t, policy_node_tr_t, musig_aggr_key_info_t) from 16-bit relative offsets to native pointers. MAX_WALLET_POLICY_BYTES is raised from 896 to 1024 (Nano X) or 1536 (other devices), and MAX_POLICY_KEY_INFO_LEN is increased to account for deeper key origin info. A new _Static_assert ensures policy_node_keyexpr_t size is a multiple of the allocator alignment so multi() key arrays remain contiguous. The code generator for BIP-388 spec tests, the parser, the script compiler, the cleartext matcher, and unit tests are all updated to use direct pointer access. No CVE, advisory, or security disclosure is referenced in the commit or supplied materials.
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.pytests/test_register_wallet.pyunit-tests/test_cleartext.cunit-tests/test_wallet.cInspect captured patch +412 / −558
### 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
@@ -6,7 +6,6 @@
/* SDK headers */
#include "bip32.h"
#include "buffer.h"
-#include "ledger_assert.h"
/* Local headers */
#include "constants.h"
@@ -30,14 +29,14 @@
#define WALLET_POLICY_VERSION_V2 2 // the current full version
// The string describing a pubkey can contain:
-// - (optional) the key origin info, which we limit to 46 bytes (2 + 8 + 3*12 = 46 bytes)
+// - (optional) the key origin info, which we limit to 46 bytes (2 + 8 + 8*12 = 106 bytes)
// - the xpub itself (up to 113 characters)
// - optional, the "/**" suffix.
// Therefore, the total length of the key info string is at most 162 bytes.
-#define MAX_POLICY_KEY_INFO_LEN_V1 (46 + MAX_SERIALIZED_PUBKEY_LENGTH + 3)
+#define MAX_POLICY_KEY_INFO_LEN_V1 (106 + MAX_SERIALIZED_PUBKEY_LENGTH + 3)
// In V1, there is no "/**" suffix, as that is no longer part of the key
-#define MAX_POLICY_KEY_INFO_LEN_V2 (46 + MAX_SERIALIZED_PUBKEY_LENGTH)
+#define MAX_POLICY_KEY_INFO_LEN_V2 (106 + MAX_SERIALIZED_PUBKEY_LENGTH)
#define MAX_POLICY_KEY_INFO_LEN MAX(MAX_POLICY_KEY_INFO_LEN_V1, MAX_POLICY_KEY_INFO_LEN_V2)
@@ -52,7 +51,17 @@
// 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
-#define MAX_WALLET_POLICY_BYTES 896
+
+// 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.
+#ifdef TARGET_NANOX
+// The Nano X has considerably less RAM than the other devices, therefore we keep the budget
+// smaller - which might reject some very large policies.
+#define MAX_WALLET_POLICY_BYTES 1024
+#else
+#define MAX_WALLET_POLICY_BYTES (384 * sizeof(void *)) // 1536 on the real devices
+#endif
#define MAX_DESCRIPTOR_TEMPLATE_LENGTH \
MAX(MAX_DESCRIPTOR_TEMPLATE_LENGTH_V1, MAX_DESCRIPTOR_TEMPLATE_LENGTH_V2)
@@ -75,7 +84,7 @@
// This limit is extremely unlikely to be hit in practice.
#define MAX_N_IN_THRESH 24
-// at most 92 bytes
+// at most 140 bytes
// wallet type (1 byte)
// name length (1 byte)
// name (max MAX_WALLET_NAME_LENGTH bytes)
@@ -86,7 +95,7 @@
#define MAX_WALLET_POLICY_SERIALIZED_LENGTH_V1 \
(1 + 1 + MAX_WALLET_NAME_LENGTH + 1 + MAX_DESCRIPTOR_TEMPLATE_LENGTH_V1 + 1 + 32)
-// at most 100 bytes
+// at most 148 bytes
// wallet type (1 byte)
// name length (1 byte)
// name (max MAX_WALLET_NAME_LENGTH bytes)
@@ -187,74 +196,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 {
@@ -265,11 +213,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
@@ -305,15 +251,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()
@@ -331,7 +274,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>/*
@@ -345,78 +288,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 {
@@ -429,26 +365,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));
@@ -2088,15 +2057,14 @@ int is_policy_sane(dispatcher_context_t *dispatcher_context,
// musig placeholders are disjoint, as long as they are not exactly the same set of
// keys. Similarly, a key used in a normal placeholder could also be part of the set of
// keys in a musig placeholder.
+ // are_key_placeholders_identical() already compares the keys themselves (the key index
+ // for plain placeholders, the whole set of key indexes for musig ones), so there is
+ // nothing left to compare but the derivations.
if (are_key_placeholders_identical(kp_i, kp_j)) {
- if (kp_i->k.key_index == kp_j->k.key_index) {
- if (kp_i->num_first == kp_j->num_first || kp_i->num_first == kp_j->num_second ||
- kp_i->num_second == kp_j->num_first ||
- kp_i->num_second == kp_j->num_second) {
- return WITH_ERROR(
- -1,
- "Key expressions with repeated derivations in miniscript");
- }
+ if (kp_i->num_first == kp_j->num_first || kp_i->num_first == kp_j->num_second ||
+ kp_i->num_second == kp_j->num_first || kp_i->num_second == kp_j->num_second) {
+ return WITH_ERROR(-1,
+ "Key expressions with repeated derivations in miniscript");
}
}
}
### 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);
### tests/test_register_wallet.py
@@ -569,7 +569,7 @@ def test_register_wallet_deep_wrapper_chain(client: RaggerClient):
"""A policy far deeper than its template must be refused, without crashing the app."""
# "n:" maps B -> B, so the chain type-checks whatever its length, and each wrapper adds an AST
# level for one template byte. 59 of them describe a 60-level policy in 74 bytes, and still fit
- # the app's 896-byte policy buffer, so the deep walk is really reached.
+ # the app's policy buffer (MAX_WALLET_POLICY_BYTES), so the deep walk is really reached.
wallet = WalletPolicy(
name="Wrapper chain",
descriptor_template="wsh(" + "n" * 59 + ":pk(@0/**))",
### unit-tests/test_cleartext.c
@@ -147,7 +147,7 @@ static void test_ct_to_cleartext(void **state) {
// A generous buffer: some cases below build large taptrees whose parsed form
// does not fit in POLICY_BUF_SIZE.
-#define BIG_POLICY_BUF_SIZE 4096
+#define BIG_POLICY_BUF_SIZE 8192
static const policy_node_t *parse_or_fail(const char *tmpl, uint8_t *buf, size_t bufsize) {
int r = parse_template(tmpl, buf, bufsize);
### unit-tests/test_wallet.c
@@ -22,10 +22,6 @@ static int parse_policy(const char *descriptor_template, uint8_t *out, size_t ou
WALLET_POLICY_VERSION_V2);
}
-// in unit tests, size_t integers are currently 8 compiled as 8 bytes; therefore, in the app
-// about half of the memory would be needed
-#define MAX_WALLET_POLICY_MEMORY_SIZE 512
-
// convenience function to compactly check common assertions on a pointer to a key expression with a
// single key
static void check_key_expr_plain(const policy_node_keyexpr_t *ptr,
@@ -45,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]);
}
@@ -58,21 +54,21 @@ static void check_key_expr_musig(const policy_node_keyexpr_t *ptr,
static void test_parse_policy_map_singlesig_1(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res = parse_policy("pkh(@0/**)", out, sizeof(out));
assert_true(res >= 0);
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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res = parse_policy("sh(wpkh(@0/**))", out, sizeof(out));
@@ -81,16 +77,16 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res = parse_policy("sh(wsh(pkh(@0/**)))", out, sizeof(out));
@@ -99,20 +95,20 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res = parse_policy("sortedmulti(2,@0/**,@1/**,@2/**)", out, sizeof(out));
@@ -122,15 +118,15 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res = parse_policy("wsh(multi(3,@0/**,@1/**,@2/**,@3/**,@4/**))", out, sizeof(out));
@@ -139,20 +135,20 @@ 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);
}
}
static void test_parse_policy_map_multisig_3(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res =
parse_policy("sh(wsh(sortedmulti(3,@0/**,@1/**,@2/**,@3/**,@4/**)))", out, sizeof(out));
@@ -162,23 +158,23 @@ 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);
}
}
static void test_parse_policy_tr(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res;
// Simple tr without a tree
@@ -187,60 +183,55 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res;
// tr with a tree with two scripts: a multi_a and a sortedmulti_a:
@@ -252,44 +243,40 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res;
res = parse_policy("tr(musig(@2,@0,@1)/<3;13>/*)", out, sizeof(out));
@@ -298,15 +285,15 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
int res;
// tr with a musig in the script path
@@ -317,20 +304,20 @@ 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) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
policy_node_t *policy = (policy_node_t *) out;
// legacy policies (returning -1)
@@ -364,7 +351,7 @@ static void test_get_policy_segwit_version(void **state) {
static void test_parse_unsigned_decimal_overflow(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(0 > parse_policy("wsh(older(5368709120))", out, sizeof(out)));
}
@@ -374,13 +361,13 @@ static void test_parse_unsigned_decimal_overflow(void **state) {
static void test_parse_keyexpr_multipath_hardened_boundary(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
// 0x7fffffff (2147483647) is the largest valid unhardened index: still accepted.
int res = parse_policy("pkh(@0/<2147483647;0>/*)", out, sizeof(out));
assert_true(res >= 0);
policy_node_with_key_t *node_1 = (policy_node_with_key_t *) out;
- check_key_expr_plain(r_policy_node_keyexpr(&node_1->key), 0, 2147483647, 0);
+ check_key_expr_plain(node_1->key, 0, 2147483647, 0);
// 0x80000000 (2147483648) is the first hardened index: must be rejected for both M and N.
assert_true(0 > parse_policy("pkh(@0/<2147483648;0>/*)", out, sizeof(out)));
@@ -390,7 +377,7 @@ static void test_parse_keyexpr_multipath_hardened_boundary(void **state) {
static void test_failures(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
// excess byte not allowed
assert_true(0 > parse_policy("pkh(@0/**) ", out, sizeof(out)));
@@ -500,8 +487,8 @@ static void Test(const char *ms, const char *hexscript, int mode, int opslimit,
strcpy(descriptor_tr, "tr(@0/<100;101>/*,");
strcat(descriptor_tr, ms);
strcat(descriptor_tr, ")");
- uint8_t out_wsh[MAX_WALLET_POLICY_MEMORY_SIZE];
- uint8_t out_tr[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out_wsh[MAX_WALLET_POLICY_BYTES];
+ uint8_t out_tr[MAX_WALLET_POLICY_BYTES];
uint8_t *out;
@@ -550,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;
}
@@ -742,7 +729,7 @@ static int traverse_collect_cb(const policy_node_t *node, void *state_) {
static void test_traverse_single_leaf(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("pkh(@0/**)", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -755,7 +742,7 @@ static void test_traverse_single_leaf(void **state) {
static void test_traverse_wsh_multi(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("wsh(multi(2,@0/**,@1/**))", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -770,7 +757,7 @@ static void test_traverse_wsh_multi(void **state) {
static void test_traverse_or_i(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("wsh(or_i(pk(@0/**),pk(@1/**)))", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -786,7 +773,7 @@ static void test_traverse_or_i(void **state) {
static void test_traverse_andor(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("wsh(c:andor(0,pk_k(@0/**),pk_k(@1/**)))", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -804,7 +791,7 @@ static void test_traverse_andor(void **state) {
static void test_traverse_thresh(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("wsh(thresh(2,c:pk_k(@0/**),ac:pk_k(@1/**),ac:pk_k(@2/**)))",
out,
sizeof(out)) >= 0);
@@ -834,7 +821,7 @@ static void test_traverse_thresh(void **state) {
static void test_traverse_tr_no_script(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("tr(@0/**)", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -848,7 +835,7 @@ static void test_traverse_tr_no_script(void **state) {
static void test_traverse_tr_one_leaf(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("tr(@0/**,pk(@1/**))", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -864,7 +851,7 @@ static void test_traverse_tr_one_leaf(void **state) {
static void test_traverse_tr_two_leaves(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("tr(@0/**,{pk(@1/**),pk(@2/**)})", out, sizeof(out)) >= 0);
traverse_collect_t s = {.count = 0, .max_visits = -1};
@@ -884,7 +871,7 @@ static void test_traverse_tr_two_leaves(void **state) {
static void test_traverse_tr_nested_tree(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
// tr(@0/**,{pk(@1/**),{pk(@2/**),pk(@3/**)}}) — nested taptree
assert_true(parse_policy("tr(@0/**,{pk(@1/**),{pk(@2/**),pk(@3/**)}})", out, sizeof(out)) >= 0);
@@ -905,7 +892,7 @@ static void test_traverse_tr_nested_tree(void **state) {
static void test_traverse_callback_abort(void **state) {
(void) state;
- uint8_t out[MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[MAX_WALLET_POLICY_BYTES];
assert_true(parse_policy("wsh(or_i(pk(@0/**),pk(@1/**)))", out, sizeof(out)) >= 0);
// The DFS order is: TOKEN_WSH, TOKEN_OR_I, TOKEN_PK, TOKEN_PK.
@@ -943,7 +930,7 @@ static void test_parse_policy_max_depth_wrappers(void **state) {
(void) state;
// deep policies need more memory than the simple ones of the other tests
- uint8_t out[4 * MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[4 * MAX_WALLET_POLICY_BYTES];
char policy[MAX_DESCRIPTOR_TEMPLATE_LENGTH + 1];
// the script inside wsh() is at depth 1, therefore one wrapper less than the limit fits
@@ -965,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);
@@ -986,14 +973,14 @@ static void make_thresh_chain(char *out, size_t out_size, int n_levels) {
static void test_parse_policy_max_thresh_nesting(void **state) {
(void) state;
- uint8_t out[4 * MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[4 * MAX_WALLET_POLICY_BYTES];
char policy[MAX_DESCRIPTOR_TEMPLATE_LENGTH + 1];
make_thresh_chain(policy, sizeof(policy), MAX_THRESH_NESTING);
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);
@@ -1025,19 +1012,19 @@ static void make_wide_thresh(char *out, size_t out_size, int n_branches) {
static void test_max_n_in_thresh(void **state) {
(void) state;
- uint8_t out[4 * MAX_WALLET_POLICY_MEMORY_SIZE];
+ uint8_t out[4 * MAX_WALLET_POLICY_BYTES];
char policy[MAX_DESCRIPTOR_TEMPLATE_LENGTH + 1];
policy_node_ext_info_t ext_info;
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 27/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.