@@ -868,10 +868,26 @@ where
868
868
let mut q_zero_right = best_compilations ( policy_cache, & subs[ 1 ] , sat_prob, None ) ?;
869
869
let mut q_zero_left = best_compilations ( policy_cache, & subs[ 0 ] , sat_prob, None ) ?;
870
870
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
+
875
891
let mut zero_comp = BTreeMap :: new ( ) ;
876
892
zero_comp. insert (
877
893
CompilationKey :: from_type (
@@ -885,6 +901,7 @@ where
885
901
compile_tern ! ( & mut right, & mut q_zero_left, & mut zero_comp, [ 1.0 , 0.0 ] ) ;
886
902
}
887
903
Concrete :: Or ( ref subs) => {
904
+ assert_eq ! ( subs. len( ) , 2 , "or takes 2 args" ) ;
888
905
let total = ( subs[ 0 ] . 0 + subs[ 1 ] . 0 ) as f64 ;
889
906
let lw = subs[ 0 ] . 0 as f64 / total;
890
907
let rw = subs[ 1 ] . 0 as f64 / total;
@@ -1039,7 +1056,11 @@ where
1039
1056
for key in key_vec {
1040
1057
k_vec. push ( KeyExpr :: SingleKey ( key) )
1041
1058
}
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
+ }
1043
1064
}
1044
1065
SigType :: Ecdsa
1045
1066
if key_vec. len ( ) == subs. len ( ) && subs. len ( ) <= MAX_PUBKEYS_PER_MULTISIG =>
@@ -1216,7 +1237,7 @@ mod tests {
1216
1237
use crate :: policy:: Liftable ;
1217
1238
use crate :: script_num_size;
1218
1239
1219
- type SPolicy = Concrete < String > ;
1240
+ type StringPolicy = Concrete < String > ;
1220
1241
type BPolicy = Concrete < bitcoin:: PublicKey > ;
1221
1242
type DummyTapAstElemExt = policy:: compiler:: AstElemExt < String , Tap > ;
1222
1243
type SegwitMiniScript = Miniscript < bitcoin:: PublicKey , Segwitv0 > ;
@@ -1247,7 +1268,7 @@ mod tests {
1247
1268
}
1248
1269
1249
1270
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" ) ;
1251
1272
let miniscript: Miniscript < String , Segwitv0 > = policy. compile ( ) ?;
1252
1273
1253
1274
assert_eq ! (
@@ -1257,18 +1278,139 @@ mod tests {
1257
1278
Ok ( ( ) )
1258
1279
}
1259
1280
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
+
1260
1402
#[ test]
1261
1403
fn compile_timelocks ( ) {
1262
1404
// 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 ! [
1264
1406
Concrete :: Key ( "A" . to_string( ) ) ,
1265
1407
Concrete :: And ( vec![ Concrete :: After ( 9 ) , Concrete :: After ( 1000_000_000 ) ] ) ,
1266
1408
] ) ;
1267
1409
assert ! ( pol. compile:: <Segwitv0 >( ) . is_err( ) ) ;
1268
1410
1269
1411
// 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))))" )
1272
1414
. unwrap ( ) ;
1273
1415
assert ! ( pol. compile:: <Segwitv0 >( ) . is_ok( ) ) ;
1274
1416
}
@@ -1307,7 +1449,7 @@ mod tests {
1307
1449
1308
1450
#[ test]
1309
1451
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" ) ;
1311
1453
let compilation: DummyTapAstElemExt =
1312
1454
best_t ( & mut BTreeMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
1313
1455
@@ -1318,7 +1460,7 @@ mod tests {
1318
1460
) ;
1319
1461
1320
1462
// compile into taproot context to avoid limit errors
1321
- let policy = SPolicy :: from_str (
1463
+ let policy = StringPolicy :: from_str (
1322
1464
"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)))"
1323
1465
) . expect ( "parsing" ) ;
1324
1466
let compilation: DummyTapAstElemExt =
0 commit comments