descriptor: add elements wallet policy tests
What changed, and why it matters
This commit only adds new test cases for Elements/Liquid confidential wallet policies. It does not change any library code, only test files. There is no security fix or vulnerability introduced here.
No action required; this is a test-only change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit extends descriptor tests in src/ctest/test_descriptor.c and src/test/test_descriptor.py to cover Elements confidential wallet policies (ct(), slip77(), elip150 blinding keys). It renames g_policy_maps to g_vars, adds new key-variable maps, and adds positive and negative test vectors. No production code is modified.
Changed components
src/ctest/test_descriptor.csrc/test/test_descriptor.pyInspect captured patch +112 / −14
diff --git a/src/ctest/test_descriptor.c b/src/ctest/test_descriptor.c
index 1990e91..93cb744 100644
--- a/src/ctest/test_descriptor.c
+++ b/src/ctest/test_descriptor.c
@@ -50,34 +50,39 @@ static struct wally_map_item g_key_map_items[] = {
{ B("slip77_key"), B("b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04") }
};
-static const struct wally_map g_key_map = {
- g_key_map_items,
- NUM_ELEMS(g_key_map_items),
- NUM_ELEMS(g_key_map_items),
- NULL
-};
-
static struct wally_map_item g_policy_map_items[] = {
+ { B("@B"), B("b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04") },
{ B("@0"), B("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL") },
{ B("@1"), B("xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU") }
};
+static struct wally_map_item g_elip150_map_items[] = {
+ { B("@B"), B("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL") },
+ { B("@0"), B("xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU") }
+};
+
/* key-variable maps for policy testing.
* The bip refers to these as "key information vectors".
*/
-static const struct wally_map g_policy_maps[3] = {
+static struct wally_map g_vars[] = {
/* Standard convenience key map for more readable test cases */
- g_key_map,
+ { g_key_map_items, NUM_ELEMS(g_key_map_items), NUM_ELEMS(g_key_map_items), NULL },
/* Wallet policy key map with 1 element "@0" */
- { g_policy_map_items, 1, 1, NULL },
+ { &g_policy_map_items[1], 1, 1, NULL },
/* Wallet policy key map with 2 elements "@0", "@1" */
- { g_policy_map_items, 2, 2, NULL }
+ { &g_policy_map_items[1], 2, 2, NULL },
+ /* Confidential wallet policy key map with 2 elements "@B", "@0" */
+ { &g_policy_map_items[0], 2, 2, NULL },
+ /* Confidential wallet policy key map with 2 elements "@B", "@0" - @B is an elip150 key */
+ { &g_elip150_map_items[0], 2, 2, NULL }
};
+/* Indices into g_vars */
#define VARS_STD 0
#define VARS_P_1 1
#define VARS_P_2 2
#define VARS_P_B 3
+#define VARS_PKB 4
static const uint32_t g_miniscript_index_0 = 0;
static const uint32_t g_miniscript_index_16 = 0x10;
@@ -1092,6 +1097,34 @@ static const struct descriptor_test {
"a9146cc69bc5443e97b8a30918cb6297ba4efb3d6dc387",
"45w36ywr", VARS_P_2
},
+#ifdef BUILD_ELEMENTS
+ /* Elements/Confidential wallet policies */
+ {
+ "policy - single asterisk reconciliation (elements)",
+ "elpkh(mainnet_xpub/*)",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL, 0,
+ "76a914bb57ca9e62c7084081edc68d2cbc9524a523784288ac",
+ "j4aaf0ll", VARS_STD
+ }, {
+ "policy - single asterisk (elements)",
+ "elpkh(@0/*)", // Becomes "elpkh(mainnet_xpub/*)" i.e. the test case above this
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL, WALLY_MINISCRIPT_POLICY_TEMPLATE,
+ "76a914bb57ca9e62c7084081edc68d2cbc9524a523784288ac",
+ "j4aaf0ll", VARS_P_1
+ }, {
+ "ct policy - reconcile 'single asterisk (elements)'",
+ "ct(slip77(@B),elpkh(@0/*))", // Becomes "elpkh(mainnet_xpub/*)"
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL, WALLY_MINISCRIPT_POLICY_TEMPLATE,
+ "76a914bb57ca9e62c7084081edc68d2cbc9524a523784288ac",
+ "a9kmw73l", VARS_P_B
+ }, {
+ "ct policy - elip150 pkh",
+ "ct(@B,elpkh(@0/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL, WALLY_MINISCRIPT_POLICY_TEMPLATE,
+ "76a91462efbe8dc3addddf826260b6be0fac3489b606e088ac",
+ "q5gxyjhu", VARS_PKB
+ },
+#endif
/*
* Misc error cases (code coverage)
*/
@@ -1676,6 +1709,43 @@ static const struct descriptor_test {
"ct(0202fc9a38e765d955e9b0bcc18fa9ae81b0c893e2dd1ef5542a9c73780a086b90,elwpkh(key_4))",
WALLY_NETWORK_LIQUID, 0, 0, 0, NULL, 0, NULL, "", VARS_STD
}
+ /* Elements/Confidential wallet policy error cases */
+ , {
+ "ct policy errchk - No substitutions",
+ "ct(slip77(b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04),elpkh(xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_1
+ }, {
+ "ct policy errchk - No blinding key substitution",
+ "ct(slip77(b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04),elpkh(@0/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_B
+ }, {
+ "ct policy errchk - No blinding key in vars",
+ "ct(slip77(@B),elpkh(@0/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_1
+ }, {
+ "ct policy errchk - blinding key with child path",
+ "ct(slip77(@B/**),elpkh(@0/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_B
+ }, {
+ "ct policy errchk - key without child path",
+ "ct(slip77(@B),elpkh(@0))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_B
+ }, {
+ "ct policy errchk - elip150 blinding key with child path",
+ "ct(@B/**,elpkh(@0/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_PKB
+ }, {
+ "ct policy errchk - elip150 with no blinding key substitution",
+ "ct(@0/**,elpkh(@1/**))",
+ WALLY_NETWORK_LIQUID, 0, 0, 0, NULL,
+ WALLY_MINISCRIPT_POLICY_TEMPLATE, NULL, "", VARS_P_2
+ },
#endif /* BUILD_ELEMENTS */
};
@@ -2270,7 +2340,7 @@ static bool check_descriptor_to_script(const struct descriptor_test* test)
uint32_t multi_index = 0;
uint32_t child_num = test->child_num ? *test->child_num : 0, features;
const bool is_policy = test->flags & WALLY_MINISCRIPT_POLICY_TEMPLATE;
- const struct wally_map *keys = &g_policy_maps[test->policy_map_index];
+ const struct wally_map *keys = &g_vars[test->policy_map_index];
/* Parse the descriptor. */
expected_ret = test->script ? WALLY_OK : WALLY_EINVAL;
@@ -2416,8 +2486,8 @@ static bool check_descriptor_to_address(const struct address_test *test)
size_t i;
int ret, expected_ret = *test->addresses[0] ? WALLY_OK : WALLY_EINVAL;
- ret = wally_descriptor_parse(test->descriptor, &g_key_map, test->network,
- flags, &descriptor);
+ ret = wally_descriptor_parse(test->descriptor, &g_vars[VARS_STD],
+ test->network, flags, &descriptor);
if (expected_ret == WALLY_OK || ret == expected_ret) {
/* For failure cases, we may fail when generating instead of parsing,
diff --git a/src/test/test_descriptor.py b/src/test/test_descriptor.py
index b143901..6cc5b54 100644
--- a/src/test/test_descriptor.py
+++ b/src/test/test_descriptor.py
@@ -338,6 +338,7 @@ class DescriptorTests(unittest.TestCase):
def test_policy(self):
"""Test policy parsing"""
# Substitution variables
+ slip77 = 'b2396b3ee20509cdb64fe24180a14a72dbd671728eaa49bac69d2bdecb5f5a04'
xpriv = 'xprvA2YKGLieCs6cWCiczALiH1jzk3VCCS5M1pGQfWPkamCdR9UpBgE2Gb8AKAyVjKHkz8v37avcfRjdcnP19dVAmZrvZQfvTcXXSAiFNQ6tTtU'
xpub1 = 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL'
xpub2 = 'xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU'
@@ -385,6 +386,33 @@ class DescriptorTests(unittest.TestCase):
self.assertEqual(ret, WALLY_EINVAL)
wally_map_free(keys)
+ # Elements confidential policy parsing"""
+ if not wally_is_elements_build()[1]:
+ return # Not enabled
+
+ P = POLICY
+ cases = [
+ # slip77 with a 64 byte hex slip77 blinding key
+ [P, 'ct(slip77(@B),elpkh(@0/*))', {'@B': slip77, '@0': xpub1}],
+ # elip150 with a 64 byte hex private blinding key
+ [P, 'ct(@B,elpkh(@0/*))', {'@B': slip77, '@0': xpub1}],
+ # elip150 with an xpub blinding key
+ [P, 'ct(@B,elpkh(@0/*))', {'@B': xpub1, '@0': xpub2}],
+ ]
+ d = c_void_p()
+ for flags, policy, key_items in cases:
+ keys = wally_map_from_dict(key_items)
+ ret = wally_descriptor_parse(policy, keys, NETWORK_LIQUID, flags, d)
+ self.assertEqual(ret, WALLY_OK)
+ ret, num_keys = wally_descriptor_get_num_keys(d)
+ self.assertEqual((ret, num_keys), (WALLY_OK, 1)) # Only non-blinding
+ ret, key_str = wally_descriptor_get_key(d, 0)
+ self.assertEqual((ret, key_str), (WALLY_OK, key_items['@0']))
+ ret, key_info = wally_descriptor_get_key(d, BLINDING_KEY_INDEX)
+ self.assertEqual((ret, key_info), (WALLY_OK, key_items['@B']))
+ wally_map_free(keys)
+ wally_descriptor_free(d)
+
def test_key_iteration(self):
"""Test iterating descriptor keys"""
origin_fp = 'd34db33f'
Why this scored 14/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.