Skip to content

Commit 2658df1

Browse files
committed
descriptor: allow fetching the blinding key from ct descriptors
1 parent eb9c9b6 commit 2658df1

File tree

4 files changed

+58
-5
lines changed

4 files changed

+58
-5
lines changed

include/wally_descriptor.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ struct wally_descriptor;
3939
/*** ms-canonicalization-flags Miniscript/Descriptor canonicalization flags */
4040
#define WALLY_MS_CANONICAL_NO_CHECKSUM 0x01 /** Do not include a checksum */
4141

42+
#define WALLY_MS_BLINDING_KEY_INDEX 0xffffffff /* Key index for confidential blinding key */
43+
4244
/**
4345
* Parse an output descriptor or miniscript expression.
4446
*
@@ -196,7 +198,8 @@ WALLY_CORE_API int wally_descriptor_get_depth(
196198
* :param descriptor: Parsed output descriptor or miniscript expression.
197199
* :param value_out: Destination for the number of keys.
198200
*
199-
* .. note:: Repeated keys are counted once for each time they appear.
201+
* .. note:: Repeated keys are counted once for each time they appear, and any
202+
*| blinding key within the descriptor is not included in the count.
200203
*/
201204
WALLY_CORE_API int wally_descriptor_get_num_keys(
202205
const struct wally_descriptor *descriptor,
@@ -206,13 +209,16 @@ WALLY_CORE_API int wally_descriptor_get_num_keys(
206209
* Get the string representation of a key in a parsed output descriptor or miniscript expression.
207210
*
208211
* :param descriptor: Parsed output descriptor or miniscript expression.
209-
* :param index: The zero-based index of the key to get.
212+
* :param index: The zero-based index of the key to get, or `WALLY_MS_BLINDING_KEY_INDEX`
213+
*| to fetch the descriptors blinding key representaton (if any).
210214
* :param output: Destination for the resulting string representation.
211215
*| The string returned should be freed using `wally_free_string`.
212216
*
213217
* .. note:: Keys may be BIP32 xpub/xpriv, WIF or hex pubkeys, and may be
214218
*| x-only. The caller can use `wally_descriptor_get_key_features` to
215219
*| determine the type of a given key.
220+
*
221+
* .. note:: Raw private blinding keys are returned as hex, not WIF.
216222
*/
217223
WALLY_CORE_API int wally_descriptor_get_key(
218224
const struct wally_descriptor *descriptor,
@@ -223,7 +229,8 @@ WALLY_CORE_API int wally_descriptor_get_key(
223229
* Get the features of a key in a parsed output descriptor or miniscript expression.
224230
*
225231
* :param descriptor: Parsed output descriptor or miniscript expression.
226-
* :param index: The zero-based index of the key to get.
232+
* :param index: The zero-based index of the key to get, or `WALLY_MS_BLINDING_KEY_INDEX`
233+
*| to fetch the descriptors blinding key features (if any).
227234
* :param value_out: Destination for the resulting :ref:`miniscript-features`.
228235
*/
229236
WALLY_CORE_API int wally_descriptor_get_key_features(

src/descriptor.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ static bool node_is_root(const ms_node *node)
569569
return !node->parent || node->parent->builtin;
570570
}
571571

572+
#ifdef BUILD_ELEMENTS
573+
static bool node_is_ct(const ms_node *node)
574+
{
575+
return !node->parent && node->kind == KIND_DESCRIPTOR_CT;
576+
}
577+
#endif
578+
572579
static void node_free(ms_node *node)
573580
{
574581
if (node) {
@@ -3325,14 +3332,31 @@ static const ms_node *descriptor_get_key(const struct wally_descriptor *descript
33253332
int wally_descriptor_get_key(const struct wally_descriptor *descriptor,
33263333
size_t index, char **output)
33273334
{
3328-
const ms_node *node = descriptor_get_key(descriptor, index);
3335+
const ms_node *node = NULL;
3336+
#ifdef BUILD_ELEMENTS
3337+
if (index == WALLY_MS_BLINDING_KEY_INDEX) {
3338+
if (descriptor && node_is_ct(descriptor->top_node)) {
3339+
node = descriptor->top_node->child;
3340+
if (node && node->kind == KIND_DESCRIPTOR_SLIP77)
3341+
node = node->child;
3342+
}
3343+
} else
3344+
#endif
3345+
node = descriptor_get_key(descriptor, index);
33293346

33303347
if (output)
33313348
*output = 0;
33323349
if (!node || !output)
33333350
return WALLY_EINVAL;
33343351

3352+
#ifdef BUILD_ELEMENTS
3353+
if (index == WALLY_MS_BLINDING_KEY_INDEX) {
3354+
if (node->kind == KIND_PRIVATE_KEY || node->kind == KIND_RAW)
3355+
goto return_hex;
3356+
}
3357+
#endif
33353358
if (node->kind == KIND_PUBLIC_KEY) {
3359+
return_hex:
33363360
return wally_hex_from_bytes((const unsigned char *)node->data,
33373361
node->data_len, output);
33383362
}
@@ -3354,7 +3378,17 @@ int wally_descriptor_get_key(const struct wally_descriptor *descriptor,
33543378
int wally_descriptor_get_key_features(const struct wally_descriptor *descriptor,
33553379
size_t index, uint32_t *value_out)
33563380
{
3357-
const ms_node *node = descriptor_get_key(descriptor, index);
3381+
const ms_node *node = NULL;
3382+
#ifdef BUILD_ELEMENTS
3383+
if (index == WALLY_MS_BLINDING_KEY_INDEX) {
3384+
if (descriptor && node_is_ct(descriptor->top_node)) {
3385+
node = descriptor->top_node->child;
3386+
if (node && node->kind == KIND_DESCRIPTOR_SLIP77)
3387+
node = node->child;
3388+
}
3389+
} else
3390+
#endif
3391+
node = descriptor_get_key(descriptor, index);
33583392

33593393
if (value_out)
33603394
*value_out = 0;

src/test/test_descriptor.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
NO_CHECKSUM = 0x1 # WALLY_MS_CANONICAL_NO_CHECKSUM
3434

35+
BLINDING_KEY_INDEX = 0xffffffff
36+
3537
def wally_map_from_dict(d):
3638
m = pointer(wally_map())
3739
assert(wally_map_init_alloc(len(d.keys()), None, m) == WALLY_OK)
@@ -307,6 +309,15 @@ def test_features_and_depth(self):
307309
self.assertEqual((ret, depth), (WALLY_OK, expected_depth))
308310
ret, num_keys = wally_descriptor_get_num_keys(d)
309311
self.assertEqual((ret, num_keys), (WALLY_OK, expected_keys))
312+
ret, key_info = wally_descriptor_get_key(d, BLINDING_KEY_INDEX)
313+
if descriptor.startswith('ct'):
314+
self.assertEqual(ret, WALLY_OK)
315+
expected_key_info = descriptor.split(',')[0][3:]
316+
if expected_key_info.startswith('slip77'):
317+
expected_key_info = expected_key_info[7:-1]
318+
self.assertEqual(key_info, expected_key_info)
319+
else:
320+
self.assertEqual(ret, WALLY_EINVAL)
310321
wally_descriptor_free(d)
311322
# Check the maximum depth parsing limit
312323
for limit, expected in [(depth-1, WALLY_EINVAL), (depth, WALLY_OK)]:

src/wasm_package/src/const.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export const WALLY_MINISCRIPT_TAPSCRIPT = 0x01; /** Tapscript, use x-only pubkey
130130
export const WALLY_MINISCRIPT_UNIQUE_KEYPATHS = 0x10; /** For policy templates, ensure BIP32 derivation paths differ for identical keys */
131131
export const WALLY_MINOR_VER = 4;
132132
export const WALLY_MS_ANY_BLINDING_KEY = 0xE00; /** SLIP-77, ELIP-150 or ELIP-151 blinding key present */
133+
export const WALLY_MS_BLINDING_KEY_INDEX = 0xffffffff; /* Key index for confidential blinding key */
133134
export const WALLY_MS_CANONICAL_NO_CHECKSUM = 0x01; /** Do not include a checksum */
134135
export const WALLY_MS_IS_DESCRIPTOR = 0x020; /** Contains only descriptor expressions (no miniscript) */
135136
export const WALLY_MS_IS_ELEMENTS = 0x100; /** Contains Elements expressions or was parsed as Elements */

0 commit comments

Comments
 (0)