@@ -868,10 +868,26 @@ where
868868 let mut q_zero_right = best_compilations ( policy_cache, & subs[ 1 ] , sat_prob, None ) ?;
869869 let mut q_zero_left = best_compilations ( policy_cache, & subs[ 0 ] , sat_prob, None ) ?;
870870
871- compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
872- compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
873- compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
874- compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
871+ let key_vec: Vec < Pk > = subs
872+ . iter ( )
873+ . filter_map ( |pol|
874+ if let Concrete :: Key ( ref pk) = * pol {
875+ Some ( pk. clone ( ) )
876+ } else {
877+ None
878+ }
879+ )
880+ . collect ( ) ;
881+ if key_vec. len ( ) == 2 {
882+ let musig_vec = key_vec. into_iter ( ) . map ( |pk| KeyExpr :: SingleKey ( pk) ) . collect ( ) ;
883+ insert_wrap ! ( AstElemExt :: terminal( Terminal :: PkK ( KeyExpr :: MuSig ( musig_vec) ) ) ) ;
884+ } else {
885+ compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
886+ compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
887+ compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
888+ compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
889+ }
890+
875891 let mut zero_comp = BTreeMap :: new ( ) ;
876892 zero_comp. insert (
877893 CompilationKey :: from_type (
@@ -885,6 +901,7 @@ where
885901 compile_tern ! ( & mut right, & mut q_zero_left, & mut zero_comp, [ 1.0 , 0.0 ] ) ;
886902 }
887903 Concrete :: Or ( ref subs) => {
904+ assert_eq ! ( subs. len( ) , 2 , "or takes 2 args" ) ;
888905 let total = ( subs[ 0 ] . 0 + subs[ 1 ] . 0 ) as f64 ;
889906 let lw = subs[ 0 ] . 0 as f64 / total;
890907 let rw = subs[ 1 ] . 0 as f64 / total;
@@ -1039,7 +1056,11 @@ where
10391056 for key in key_vec {
10401057 k_vec. push ( KeyExpr :: SingleKey ( key) )
10411058 }
1042- insert_wrap ! ( AstElemExt :: terminal( Terminal :: MultiA ( k, k_vec) ) )
1059+ if k == k_vec. len ( ) {
1060+ insert_wrap ! ( AstElemExt :: terminal( Terminal :: PkK ( KeyExpr :: MuSig ( k_vec) ) ) )
1061+ } else {
1062+ insert_wrap ! ( AstElemExt :: terminal( Terminal :: MultiA ( k, k_vec) ) )
1063+ }
10431064 }
10441065 SigType :: Ecdsa
10451066 if key_vec. len ( ) == subs. len ( ) && subs. len ( ) <= MAX_PUBKEYS_PER_MULTISIG =>
@@ -1216,7 +1237,7 @@ mod tests {
12161237 use crate :: policy:: Liftable ;
12171238 use crate :: script_num_size;
12181239
1219- type SPolicy = Concrete < String > ;
1240+ type StringPolicy = Concrete < String > ;
12201241 type BPolicy = Concrete < bitcoin:: PublicKey > ;
12211242 type DummyTapAstElemExt = policy:: compiler:: AstElemExt < String , Tap > ;
12221243 type SegwitMiniScript = Miniscript < bitcoin:: PublicKey , Segwitv0 > ;
@@ -1247,7 +1268,7 @@ mod tests {
12471268 }
12481269
12491270 fn policy_compile_lift_check ( s : & str ) -> Result < ( ) , CompilerError > {
1250- let policy = SPolicy :: from_str ( s) . expect ( "parse" ) ;
1271+ let policy = StringPolicy :: from_str ( s) . expect ( "parse" ) ;
12511272 let miniscript: Miniscript < String , Segwitv0 > = policy. compile ( ) ?;
12521273
12531274 assert_eq ! (
@@ -1257,18 +1278,139 @@ mod tests {
12571278 Ok ( ( ) )
12581279 }
12591280
1281+ #[ test]
1282+ fn compile_to_musig ( ) {
1283+ let pol: StringPolicy =
1284+ StringPolicy :: from_str ( "thresh(3,pk(A),pk(B),pk(C))" ) . unwrap ( ) ;
1285+ let output = pol. compile :: < Tap > ( ) ;
1286+ println ! ( "The miniscript is {}" , output. unwrap( ) ) ;
1287+
1288+ let pol: StringPolicy =
1289+ StringPolicy :: from_str ( "and(pk(A),pk(B))" ) . unwrap ( ) ;
1290+ let output = pol. compile :: < Tap > ( ) ;
1291+ println ! ( "The miniscript is {}" , output. unwrap( ) ) ;
1292+
1293+ let pol: StringPolicy =
1294+ StringPolicy :: from_str ( "thresh(2,thresh(2,pk(A),pk(B)),pk(C),pk(D))" ) . unwrap ( ) ;
1295+ let output = pol. compile :: < Tap > ( ) ;
1296+ println ! ( "The miniscript is {}" , output. unwrap( ) ) ;
1297+
1298+ let pol: StringPolicy =
1299+ StringPolicy :: from_str ( "thresh(2,pk(A),pk(B),pk(C))" ) . unwrap ( ) ;
1300+ let output = pol. compile :: < Segwitv0 > ( ) ;
1301+ println ! ( "The miniscript is {}" , output. unwrap( ) ) ;
1302+
1303+ let pol: StringPolicy =
1304+ StringPolicy :: from_str ( "thresh(2,pk(A),pk(B),pk(C))" ) . unwrap ( ) ;
1305+ let output = pol. compile :: < Tap > ( ) ;
1306+ println ! ( "The miniscript is {}" , output. unwrap( ) ) ;
1307+ }
1308+
1309+ #[ test]
1310+ fn test_internal_key_extraction ( ) {
1311+ let pol: StringPolicy =
1312+ StringPolicy :: from_str ( "thresh(1,and(pk(A1),pk(A2)),thresh(3,pk(A6),pk(A3),pk(A4)),pk(A5))" ) . unwrap ( ) ;
1313+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1314+ println ! ( "The miniscript is {}" , output) ;
1315+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1316+ // Internal key => pk(A5)
1317+ println ! ( "The taproot descriptor is {}" , taproot) ;
1318+
1319+ let pol: StringPolicy =
1320+ StringPolicy :: from_str ( "thresh(1,and(pk(A1),pk(A2)),thresh(3,pk(A6),pk(A3),pk(A4)),and(pk(A5),sha256(H)))" ) . unwrap ( ) ;
1321+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1322+ println ! ( "The miniscript is {}" , output) ;
1323+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1324+ // Internal key should be => musig(A1,A2)
1325+ println ! ( "The taproot descriptor is {}" , taproot) ;
1326+
1327+ let pol: StringPolicy =
1328+ StringPolicy :: from_str ( "thresh(1,and(pk(A1),older(9)),and(pk(A2),sha256(H)))" ) . unwrap ( ) ;
1329+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1330+ println ! ( "The miniscript is {}" , output) ;
1331+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1332+ // Internal key should be => musig(A1,A2)
1333+ println ! ( "The taproot descriptor is {}" , taproot) ;
1334+
1335+ let pol_str = "or(
1336+ 3@or(
1337+ 4@thresh(1, pk(A1), and(pk(A2), pk(A3))),
1338+ 5@thresh(1, or(pk(A4), pk(A5)), and(pk(A6), pk(A7)))
1339+ ),
1340+ 2@or(
1341+ 2@thresh(3, and(pk(A8), pk(A9)), or(pk(A10), pk(A11)), and(pk(A12), sha256(H1))),
1342+ 1@or(
1343+ 4@and(pk(A13), sha256(H2)),
1344+ 1@thresh(1, or(pk(A14), pk(A15)), and(pk(A16), pk(A17)))
1345+ )
1346+ )
1347+ )" ;
1348+ let pol_str = pol_str. replace ( & [ ' ' , '\n' ] [ ..] , "" ) ;
1349+ let pol: StringPolicy =
1350+ StringPolicy :: from_str ( pol_str. as_str ( ) ) . unwrap ( ) ;
1351+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1352+ println ! ( "The miniscript is {}" , output) ;
1353+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1354+ // Internal key should be => musig(A6,A7)
1355+ println ! ( "The taproot descriptor is {}" , taproot) ;
1356+
1357+ let pol_str = "or(
1358+ 3@or(
1359+ 4@thresh(1, pk(A1), and(pk(A2), pk(A3))),
1360+ 5@thresh(1, or(pk(A4), pk(A5)), and(pk(A6), pk(A7)))
1361+ ),
1362+ 4@or(
1363+ 2@thresh(3, pk(A8), pk(A9), pk(A10)),
1364+ 1@or(
1365+ 4@and(pk(A13), sha256(H2)),
1366+ 1@thresh(1, or(pk(A14), pk(A15)), and(pk(A16), pk(A17)))
1367+ )
1368+ )
1369+ )" ;
1370+ let pol_str = pol_str. replace ( & [ ' ' , '\n' ] [ ..] , "" ) ;
1371+ let pol: StringPolicy =
1372+ StringPolicy :: from_str ( pol_str. as_str ( ) ) . unwrap ( ) ;
1373+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1374+ println ! ( "The miniscript is {}" , output) ;
1375+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1376+ // Internal key should be => musig(A8,A9,A10)
1377+ println ! ( "The taproot descriptor is {}" , taproot) ;
1378+
1379+ let pol_str = "or(
1380+ 3@or(
1381+ 4@thresh(2, pk(A1), pk(A2), pk(A3)),
1382+ 5@thresh(2, or(pk(A4), pk(A5)), and(pk(A6), pk(A7)), pk(A18))
1383+ ),
1384+ 4@or(
1385+ 2@thresh(2, pk(A8), pk(A9), pk(A10)),
1386+ 1@or(
1387+ 4@and(pk(A13), sha256(H2)),
1388+ 1@thresh(1, or(pk(A14), pk(A15)), and(pk(A16), pk(A17)))
1389+ )
1390+ )
1391+ )" ;
1392+ let pol_str = pol_str. replace ( & [ ' ' , '\n' ] [ ..] , "" ) ;
1393+ let pol: StringPolicy =
1394+ StringPolicy :: from_str ( pol_str. as_str ( ) ) . unwrap ( ) ;
1395+ let output = pol. compile :: < Tap > ( ) . unwrap ( ) ;
1396+ println ! ( "The miniscript is {}" , output) ;
1397+ let taproot = pol. compile_tr ( Some ( "UNSPENDABLE_KEY" . to_string ( ) ) ) . unwrap ( ) ;
1398+ // Internal key should be => musig(A8,A9)
1399+ println ! ( "The taproot descriptor is {}" , taproot) ;
1400+ }
1401+
12601402 #[ test]
12611403 fn compile_timelocks ( ) {
12621404 // artificially create a policy that is problematic and try to compile
1263- let pol: SPolicy = Concrete :: And ( vec ! [
1405+ let pol: StringPolicy = Concrete :: And ( vec ! [
12641406 Concrete :: Key ( "A" . to_string( ) ) ,
12651407 Concrete :: And ( vec![ Concrete :: After ( 9 ) , Concrete :: After ( 1000_000_000 ) ] ) ,
12661408 ] ) ;
12671409 assert ! ( pol. compile:: <Segwitv0 >( ) . is_err( ) ) ;
12681410
12691411 // This should compile
1270- let pol: SPolicy =
1271- SPolicy :: from_str ( "and(pk(A),or(and(after(9),pk(B)),and(after(1000000000),pk(C))))" )
1412+ let pol: StringPolicy =
1413+ StringPolicy :: from_str ( "and(pk(A),or(and(after(9),pk(B)),and(after(1000000000),pk(C))))" )
12721414 . unwrap ( ) ;
12731415 assert ! ( pol. compile:: <Segwitv0 >( ) . is_ok( ) ) ;
12741416 }
@@ -1307,7 +1449,7 @@ mod tests {
13071449
13081450 #[ test]
13091451 fn compile_q ( ) {
1310- let policy = SPolicy :: from_str ( "or(1@and(pk(A),pk(B)),127@pk(C))" ) . expect ( "parsing" ) ;
1452+ let policy = StringPolicy :: from_str ( "or(1@and(pk(A),pk(B)),127@pk(C))" ) . expect ( "parsing" ) ;
13111453 let compilation: DummyTapAstElemExt =
13121454 best_t ( & mut BTreeMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
13131455
@@ -1318,7 +1460,7 @@ mod tests {
13181460 ) ;
13191461
13201462 // compile into taproot context to avoid limit errors
1321- let policy = SPolicy :: from_str (
1463+ let policy = StringPolicy :: from_str (
13221464 "and(and(and(or(127@thresh(2,pk(A),pk(B),thresh(2,or(127@pk(A),1@pk(B)),after(100),or(and(pk(C),after(200)),and(pk(D),sha256(66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925))),pk(E))),1@pk(F)),sha256(66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925)),or(127@pk(G),1@after(300))),or(127@after(400),pk(H)))"
13231465 ) . expect ( "parsing" ) ;
13241466 let compilation: DummyTapAstElemExt =
0 commit comments