@@ -844,6 +844,47 @@ where
844
844
None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
845
845
}
846
846
}
847
+ Terminal :: MultiA ( k, ref subs) => {
848
+ if node_state. n_evaluated == subs. len ( ) {
849
+ if node_state. n_satisfied == k {
850
+ self . stack . push ( stack:: Element :: Satisfied ) ;
851
+ } else {
852
+ self . stack . push ( stack:: Element :: Dissatisfied ) ;
853
+ }
854
+ } else {
855
+ // evaluate each key with as a pk
856
+ // note that evaluate_pk will error on non-empty incorrect sigs
857
+ // push 1 on satisfied sigs and push 0 on empty sigs
858
+ match self
859
+ . stack
860
+ . evaluate_pk ( & mut self . verify_sig , & subs[ node_state. n_evaluated ] )
861
+ {
862
+ Some ( Ok ( x) ) => {
863
+ self . push_evaluation_state (
864
+ node_state. node ,
865
+ node_state. n_evaluated + 1 ,
866
+ node_state. n_satisfied + 1 ,
867
+ ) ;
868
+ match self . stack . pop ( ) {
869
+ Some ( ..) => return Some ( Ok ( x) ) ,
870
+ None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
871
+ }
872
+ }
873
+ None => {
874
+ self . push_evaluation_state (
875
+ node_state. node ,
876
+ node_state. n_evaluated + 1 ,
877
+ node_state. n_satisfied ,
878
+ ) ;
879
+ match self . stack . pop ( ) {
880
+ Some ( ..) => { } // not-satisfied, look for next key
881
+ None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
882
+ }
883
+ }
884
+ x => return x, //forward errors as is
885
+ }
886
+ }
887
+ }
847
888
Terminal :: Multi ( ref k, ref subs) if node_state. n_evaluated == 0 => {
848
889
let len = self . stack . len ( ) ;
849
890
if len < k + 1 {
@@ -992,7 +1033,7 @@ mod tests {
992
1033
use super :: * ;
993
1034
use bitcoin;
994
1035
use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d, Hash } ;
995
- use bitcoin:: secp256k1:: { self , Secp256k1 , VerifyOnly } ;
1036
+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
996
1037
use miniscript:: context:: NoChecks ;
997
1038
use Miniscript ;
998
1039
use MiniscriptKey ;
@@ -1005,15 +1046,21 @@ mod tests {
1005
1046
Vec < Vec < u8 > > ,
1006
1047
Vec < bitcoin:: EcdsaSig > ,
1007
1048
secp256k1:: Message ,
1008
- Secp256k1 < VerifyOnly > ,
1049
+ Secp256k1 < secp256k1:: All > ,
1050
+ Vec < bitcoin:: XOnlyPublicKey > ,
1051
+ Vec < bitcoin:: SchnorrSig > ,
1052
+ Vec < Vec < u8 > > ,
1009
1053
) {
1010
- let secp_sign = secp256k1:: Secp256k1 :: signing_only ( ) ;
1011
- let secp_verify = secp256k1:: Secp256k1 :: verification_only ( ) ;
1054
+ let secp = secp256k1:: Secp256k1 :: new ( ) ;
1012
1055
let msg = secp256k1:: Message :: from_slice ( & b"Yoda: btc, I trust. HODL I must!" [ ..] )
1013
1056
. expect ( "32 bytes" ) ;
1014
1057
let mut pks = vec ! [ ] ;
1015
1058
let mut ecdsa_sigs = vec ! [ ] ;
1016
1059
let mut der_sigs = vec ! [ ] ;
1060
+ let mut x_only_pks = vec ! [ ] ;
1061
+ let mut schnorr_sigs = vec ! [ ] ;
1062
+ let mut ser_schnorr_sigs = vec ! [ ] ;
1063
+
1017
1064
let mut sk = [ 0 ; 32 ] ;
1018
1065
for i in 1 ..n + 1 {
1019
1066
sk[ 0 ] = i as u8 ;
@@ -1022,10 +1069,10 @@ mod tests {
1022
1069
1023
1070
let sk = secp256k1:: SecretKey :: from_slice ( & sk[ ..] ) . expect ( "secret key" ) ;
1024
1071
let pk = bitcoin:: PublicKey {
1025
- inner : secp256k1:: PublicKey :: from_secret_key ( & secp_sign , & sk) ,
1072
+ inner : secp256k1:: PublicKey :: from_secret_key ( & secp , & sk) ,
1026
1073
compressed : true ,
1027
1074
} ;
1028
- let sig = secp_sign . sign_ecdsa ( & msg, & sk) ;
1075
+ let sig = secp . sign_ecdsa ( & msg, & sk) ;
1029
1076
ecdsa_sigs. push ( bitcoin:: EcdsaSig {
1030
1077
sig,
1031
1078
hash_ty : bitcoin:: EcdsaSigHashType :: All ,
@@ -1034,21 +1081,41 @@ mod tests {
1034
1081
sigser. push ( 0x01 ) ; // sighash_all
1035
1082
pks. push ( pk) ;
1036
1083
der_sigs. push ( sigser) ;
1084
+
1085
+ let keypair = bitcoin:: KeyPair :: from_secret_key ( & secp, sk) ;
1086
+ x_only_pks. push ( bitcoin:: XOnlyPublicKey :: from_keypair ( & keypair) ) ;
1087
+ let schnorr_sig = secp. sign_schnorr_with_aux_rand ( & msg, & keypair, & [ 0u8 ; 32 ] ) ;
1088
+ let schnorr_sig = bitcoin:: SchnorrSig {
1089
+ sig : schnorr_sig,
1090
+ hash_ty : bitcoin:: SchnorrSigHashType :: Default ,
1091
+ } ;
1092
+ ser_schnorr_sigs. push ( schnorr_sig. to_vec ( ) ) ;
1093
+ schnorr_sigs. push ( schnorr_sig) ;
1037
1094
}
1038
- ( pks, der_sigs, ecdsa_sigs, msg, secp_verify)
1095
+ (
1096
+ pks,
1097
+ der_sigs,
1098
+ ecdsa_sigs,
1099
+ msg,
1100
+ secp,
1101
+ x_only_pks,
1102
+ schnorr_sigs,
1103
+ ser_schnorr_sigs,
1104
+ )
1039
1105
}
1040
1106
1041
1107
#[ test]
1042
1108
fn sat_constraints ( ) {
1043
- let ( pks, der_sigs, ecdsa_sigs, sighash, secp) = setup_keys_sigs ( 10 ) ;
1109
+ let ( pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) =
1110
+ setup_keys_sigs ( 10 ) ;
1044
1111
let secp_ref = & secp;
1045
1112
let vfyfn_ = |pksig : & KeySigPair | match pksig {
1046
1113
KeySigPair :: Ecdsa ( pk, ecdsa_sig) => secp_ref
1047
1114
. verify_ecdsa ( & sighash, & ecdsa_sig. sig , & pk. inner )
1048
1115
. is_ok ( ) ,
1049
- KeySigPair :: Schnorr ( _xpk , _schnorr_sig ) => {
1050
- unreachable ! ( "Schnorr sig not tested in this test" )
1051
- }
1116
+ KeySigPair :: Schnorr ( xpk , schnorr_sig ) => secp_ref
1117
+ . verify_schnorr ( & schnorr_sig . sig , & sighash , xpk )
1118
+ . is_ok ( ) ,
1052
1119
} ;
1053
1120
1054
1121
fn from_stack < ' txin , ' elem > (
@@ -1454,6 +1521,79 @@ mod tests {
1454
1521
1455
1522
let multi_error: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
1456
1523
assert ! ( multi_error. is_err( ) ) ;
1524
+
1525
+ // multi_a tests
1526
+ let stack = Stack :: from ( vec ! [
1527
+ stack:: Element :: Dissatisfied ,
1528
+ stack:: Element :: Dissatisfied ,
1529
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 2 ] ) ,
1530
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 1 ] ) ,
1531
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 0 ] ) ,
1532
+ ] ) ;
1533
+
1534
+ let elem = x_only_no_checks_ms ( & format ! (
1535
+ "multi_a(3,{},{},{},{},{})" ,
1536
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1537
+ ) ) ;
1538
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1539
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack, & elem) ;
1540
+
1541
+ let multi_a_satisfied: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
1542
+ assert_eq ! (
1543
+ multi_a_satisfied. unwrap( ) ,
1544
+ vec![
1545
+ SatisfiedConstraint :: PublicKey {
1546
+ key_sig: KeySigPair :: Schnorr ( xpks[ 0 ] , schnorr_sigs[ 0 ] )
1547
+ } ,
1548
+ SatisfiedConstraint :: PublicKey {
1549
+ key_sig: KeySigPair :: Schnorr ( xpks[ 1 ] , schnorr_sigs[ 1 ] )
1550
+ } ,
1551
+ SatisfiedConstraint :: PublicKey {
1552
+ key_sig: KeySigPair :: Schnorr ( xpks[ 2 ] , schnorr_sigs[ 2 ] )
1553
+ } ,
1554
+ ]
1555
+ ) ;
1556
+
1557
+ // multi_a tests: wrong order of sigs
1558
+ let stack = Stack :: from ( vec ! [
1559
+ stack:: Element :: Dissatisfied ,
1560
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 2 ] ) ,
1561
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 1 ] ) ,
1562
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 0 ] ) ,
1563
+ stack:: Element :: Dissatisfied ,
1564
+ ] ) ;
1565
+
1566
+ let elem = x_only_no_checks_ms ( & format ! (
1567
+ "multi_a(3,{},{},{},{},{})" ,
1568
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1569
+ ) ) ;
1570
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1571
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack. clone ( ) , & elem) ;
1572
+
1573
+ let multi_a_error: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
1574
+ assert ! ( multi_a_error. is_err( ) ) ;
1575
+
1576
+ // multi_a wrong thresh: k = 2, but three sigs
1577
+ let elem = x_only_no_checks_ms ( & format ! (
1578
+ "multi_a(2,{},{},{},{},{})" ,
1579
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1580
+ ) ) ;
1581
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1582
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack. clone ( ) , & elem) ;
1583
+
1584
+ let multi_a_error: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
1585
+ assert ! ( multi_a_error. is_err( ) ) ;
1586
+
1587
+ // multi_a correct thresh, but small stack
1588
+ let elem = x_only_no_checks_ms ( & format ! (
1589
+ "multi_a(3,{},{},{},{},{},{})" ,
1590
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] , xpks[ 5 ]
1591
+ ) ) ;
1592
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1593
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack, & elem) ;
1594
+
1595
+ let multi_a_error: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
1596
+ assert ! ( multi_a_error. is_err( ) ) ;
1457
1597
}
1458
1598
1459
1599
// By design there is no support for parse a miniscript with BitcoinKey
@@ -1463,4 +1603,10 @@ mod tests {
1463
1603
Miniscript :: from_str_insane ( ms) . unwrap ( ) ;
1464
1604
elem. to_no_checks_ms ( )
1465
1605
}
1606
+
1607
+ fn x_only_no_checks_ms ( ms : & str ) -> Miniscript < BitcoinKey , NoChecks > {
1608
+ let elem: Miniscript < bitcoin:: XOnlyPublicKey , NoChecks > =
1609
+ Miniscript :: from_str_insane ( ms) . unwrap ( ) ;
1610
+ elem. to_no_checks_ms ( )
1611
+ }
1466
1612
}
0 commit comments