18
18
#define MS_FLAGS_ALL (WALLY_MINISCRIPT_TAPSCRIPT | \
19
19
WALLY_MINISCRIPT_ONLY | \
20
20
WALLY_MINISCRIPT_REQUIRE_CHECKSUM)
21
+ #define MS_FLAGS_CANONICALIZE (WALLY_MINISCRIPT_REQUIRE_CHECKSUM | \
22
+ WALLY_MINISCRIPT_POLICY)
21
23
22
24
/* Properties and expressions definition */
23
25
#define TYPE_NONE 0x00
@@ -262,6 +264,7 @@ static const struct addr_ver_t *addr_ver_from_family(
262
264
static const struct ms_builtin_t * builtin_get (const ms_node * node );
263
265
static int generate_script (ms_ctx * ctx , ms_node * node ,
264
266
unsigned char * script , size_t script_len , size_t * written );
267
+ static bool is_valid_policy_map (const struct wally_map * map_in );
265
268
266
269
/* Wrapper for strtoll */
267
270
static bool strtoll_n (const char * str , size_t str_len , int64_t * v )
@@ -347,8 +350,10 @@ static int generate_checksum(const char *str, size_t str_len, char *checksum_out
347
350
return WALLY_OK ;
348
351
}
349
352
350
- static inline bool is_identifer_char (char c )
353
+ static inline bool is_identifer_char (char c , uint32_t flags )
351
354
{
355
+ if (flags & WALLY_MINISCRIPT_POLICY )
356
+ return (c >= '0' && c <= '9' ) || c == '@' ;
352
357
return (c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || (c >= '0' && c <= '9' ) || c == '_' ;
353
358
}
354
359
@@ -376,17 +381,20 @@ static int canonicalize(const char *descriptor,
376
381
if (output )
377
382
* output = NULL ;
378
383
379
- if (!descriptor || (flags & ~WALLY_MINISCRIPT_REQUIRE_CHECKSUM ) || !output )
384
+ if (!descriptor || (flags & ~MS_FLAGS_CANONICALIZE ) || !output )
380
385
return WALLY_EINVAL ;
381
386
387
+ if ((flags & WALLY_MINISCRIPT_POLICY ) && !is_valid_policy_map (vars_in ))
388
+ return WALLY_EINVAL ; /* Invalid policy variables given */
389
+
382
390
/* First, find the length of the canonicalized descriptor */
383
391
while (* p && * p != '#' ) {
384
- while (* p && * p != '#' && !is_identifer_char (* p )) {
392
+ while (* p && * p != '#' && !is_identifer_char (* p , flags )) {
385
393
++ required_len ;
386
394
++ p ;
387
395
}
388
396
start = p ;
389
- while (is_identifer_char (* p ))
397
+ while (is_identifer_char (* p , flags ))
390
398
++ p ;
391
399
if (p != start ) {
392
400
const bool starts_with_digit = * start >= '0' && * start <= '9' ;
@@ -410,18 +418,18 @@ static int canonicalize(const char *descriptor,
410
418
p = descriptor ;
411
419
out = * output ;
412
420
while (* p && * p != '#' ) {
413
- while (* p && * p != '#' && !is_identifer_char (* p )) {
421
+ while (* p && * p != '#' && !is_identifer_char (* p , flags )) {
414
422
* out ++ = * p ++ ;
415
423
}
416
424
start = p ;
417
- while (is_identifer_char (* p ))
425
+ while (is_identifer_char (* p , flags ))
418
426
++ p ;
419
427
if (p != start ) {
420
428
const bool is_number = * start >= '0' && * start <= '9' ;
421
429
size_t lookup_len = p - start ;
422
- if (!vars_in || lookup_len > VAR_MAX_NAME_LEN || is_number ) {
430
+ if (!vars_in || lookup_len > VAR_MAX_NAME_LEN || is_number )
423
431
memcpy (out , start , lookup_len );
424
- } else {
432
+ else {
425
433
/* Lookup the potential identifier */
426
434
const struct wally_map_item * item = lookup_identifier (vars_in , start , lookup_len );
427
435
lookup_len = item ? item -> value_len - 1 : lookup_len ;
@@ -2370,6 +2378,34 @@ static int node_generate_script(ms_ctx *ctx, uint32_t depth, uint32_t index,
2370
2378
return ret ;
2371
2379
}
2372
2380
2381
+ static bool is_valid_policy_map (const struct wally_map * map_in )
2382
+ {
2383
+ ms_ctx ctx ;
2384
+ ms_node node ;
2385
+ int64_t v ;
2386
+ size_t i ;
2387
+ int ret = WALLY_OK ;
2388
+
2389
+ memset (& ctx , 0 , sizeof (ctx ));
2390
+
2391
+ for (i = 0 ; ret == WALLY_OK && i < map_in -> num_items ; ++ i ) {
2392
+ const struct wally_map_item * item = & map_in -> items [i ];
2393
+ if (!item -> key || item -> key_len < 2 || item -> key [0 ] != '@' ||
2394
+ !strtoll_n ((const char * )item -> key + 1 , item -> key_len - 1 , & v ) || v < 0 )
2395
+ return false; /* Policy keys can only be @n */
2396
+ if (!item -> value || !item -> value_len )
2397
+ return false; /* No key value */
2398
+ memset (& node , 0 , sizeof (node ));
2399
+ node .data = (const char * )item -> value ;
2400
+ node .data_len = item -> value_len - 1 ;
2401
+ if (analyze_miniscript_key (& ctx , 0 , & node , NULL ) != WALLY_OK ||
2402
+ node .kind == KIND_PRIVATE_KEY )
2403
+ ret = WALLY_EINVAL ; /* Policy data must be an xpub */
2404
+ node_free (& node );
2405
+ }
2406
+ return ret == WALLY_OK ;
2407
+ }
2408
+
2373
2409
int wally_descriptor_parse (const char * miniscript ,
2374
2410
const struct wally_map * vars_in ,
2375
2411
uint32_t network , uint32_t flags ,
@@ -2391,8 +2427,7 @@ int wally_descriptor_parse(const char *miniscript,
2391
2427
return WALLY_ENOMEM ;
2392
2428
ctx = * output ;
2393
2429
ctx -> addr_ver = addr_ver ;
2394
- ret = canonicalize (miniscript , vars_in ,
2395
- flags & WALLY_MINISCRIPT_REQUIRE_CHECKSUM ,
2430
+ ret = canonicalize (miniscript , vars_in , flags & MS_FLAGS_CANONICALIZE ,
2396
2431
& ctx -> src );
2397
2432
if (ret == WALLY_OK ) {
2398
2433
ctx -> src_len = strlen (ctx -> src );
0 commit comments