1818#define  MS_FLAGS_ALL  (WALLY_MINISCRIPT_TAPSCRIPT | \
1919        WALLY_MINISCRIPT_ONLY | \
2020        WALLY_MINISCRIPT_REQUIRE_CHECKSUM)
21+ #define  MS_FLAGS_CANONICALIZE  (WALLY_MINISCRIPT_REQUIRE_CHECKSUM | \
22+         WALLY_MINISCRIPT_POLICY)
2123
2224/* Properties and expressions definition */ 
2325#define  TYPE_NONE   0x00
@@ -262,6 +264,7 @@ static const struct addr_ver_t *addr_ver_from_family(
262264static  const  struct  ms_builtin_t  * builtin_get (const  ms_node  * node );
263265static  int  generate_script (ms_ctx  * ctx , ms_node  * node ,
264266                           unsigned char   * script , size_t  script_len , size_t  * written );
267+ static  bool  is_valid_policy_map (const  struct  wally_map  * map_in );
265268
266269/* Wrapper for strtoll */ 
267270static  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
347350    return  WALLY_OK ;
348351}
349352
350- static  inline  bool  is_identifer_char (char  c )
353+ static  inline  bool  is_identifer_char (char  c ,  uint32_t   flags )
351354{
355+     if  (flags  &  WALLY_MINISCRIPT_POLICY )
356+         return  (c  >= '0'  &&  c  <= '9' ) ||  c  ==  '@' ;
352357    return  (c  >= 'a'  &&  c  <= 'z' ) ||  (c  >= 'A'  &&  c  <= 'Z' ) ||  (c  >= '0'  &&  c  <= '9' ) ||  c  ==  '_' ;
353358}
354359
@@ -376,17 +381,20 @@ static int canonicalize(const char *descriptor,
376381    if  (output )
377382        * output  =  NULL ;
378383
379-     if  (!descriptor  ||  (flags  &  ~WALLY_MINISCRIPT_REQUIRE_CHECKSUM ) ||  !output )
384+     if  (!descriptor  ||  (flags  &  ~MS_FLAGS_CANONICALIZE ) ||  !output )
380385        return  WALLY_EINVAL ;
381386
387+     if  ((flags  &  WALLY_MINISCRIPT_POLICY ) &&  !is_valid_policy_map (vars_in ))
388+         return  WALLY_EINVAL ; /* Invalid policy variables given */ 
389+ 
382390    /* First, find the length of the canonicalized descriptor */ 
383391    while  (* p  &&  * p  !=  '#' ) {
384-         while  (* p  &&  * p  !=  '#'  &&  !is_identifer_char (* p )) {
392+         while  (* p  &&  * p  !=  '#'  &&  !is_identifer_char (* p ,  flags )) {
385393            ++ required_len ;
386394            ++ p ;
387395        }
388396        start  =  p ;
389-         while  (is_identifer_char (* p ))
397+         while  (is_identifer_char (* p ,  flags ))
390398            ++ p ;
391399        if  (p  !=  start ) {
392400            const  bool  starts_with_digit  =  * start  >= '0'  &&  * start  <= '9' ;
@@ -410,18 +418,18 @@ static int canonicalize(const char *descriptor,
410418    p  =  descriptor ;
411419    out  =  * output ;
412420    while  (* p  &&  * p  !=  '#' ) {
413-         while  (* p  &&  * p  !=  '#'  &&  !is_identifer_char (* p )) {
421+         while  (* p  &&  * p  !=  '#'  &&  !is_identifer_char (* p ,  flags )) {
414422            * out ++  =  * p ++ ;
415423        }
416424        start  =  p ;
417-         while  (is_identifer_char (* p ))
425+         while  (is_identifer_char (* p ,  flags ))
418426            ++ p ;
419427        if  (p  !=  start ) {
420428            const  bool  is_number  =  * start  >= '0'  &&  * start  <= '9' ;
421429            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 )
423431                memcpy (out , start , lookup_len );
424-             }  else  {
432+             else  {
425433                /* Lookup the potential identifier */ 
426434                const  struct  wally_map_item  * item  =  lookup_identifier (vars_in , start , lookup_len );
427435                lookup_len  =  item  ? item -> value_len  -  1  : lookup_len ;
@@ -2370,6 +2378,35 @@ static int node_generate_script(ms_ctx *ctx, uint32_t depth, uint32_t index,
23702378    return  ret ;
23712379}
23722380
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+         if  (!(node  =  wally_calloc (sizeof (* node ))))
2399+             return  false;
2400+         node -> data  =  (const  char * )item -> value ;
2401+         node -> data_len  =  item -> value_len  -  1 ;
2402+         if  (analyze_miniscript_key (& ctx , 0 , node , NULL ) !=  WALLY_OK  || 
2403+             node -> kind  ==  KIND_PRIVATE_KEY )
2404+             ret  =  WALLY_EINVAL ; /* Policy data must be an xpub */ 
2405+         node_free (node );
2406+     }
2407+     return  ret  ==  WALLY_OK ;
2408+ }
2409+ 
23732410int  wally_descriptor_parse (const  char  * miniscript ,
23742411                           const  struct  wally_map  * vars_in ,
23752412                           uint32_t  network , uint32_t  flags ,
@@ -2391,8 +2428,7 @@ int wally_descriptor_parse(const char *miniscript,
23912428        return  WALLY_ENOMEM ;
23922429    ctx  =  * output ;
23932430    ctx -> addr_ver  =  addr_ver ;
2394-     ret  =  canonicalize (miniscript , vars_in ,
2395-                        flags  &  WALLY_MINISCRIPT_REQUIRE_CHECKSUM ,
2431+     ret  =  canonicalize (miniscript , vars_in , flags  &  MS_FLAGS_CANONICALIZE ,
23962432                       & ctx -> src );
23972433    if  (ret  ==  WALLY_OK ) {
23982434        ctx -> src_len  =  strlen (ctx -> src );
0 commit comments