@@ -844,6 +844,47 @@ where
844844 None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
845845 }
846846 }
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+ }
847888 Terminal :: Multi ( ref k, ref subs) if node_state. n_evaluated == 0 => {
848889 let len = self . stack . len ( ) ;
849890 if len < k + 1 {
@@ -992,7 +1033,7 @@ mod tests {
9921033 use super :: * ;
9931034 use bitcoin;
9941035 use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d, Hash } ;
995- use bitcoin:: secp256k1:: { self , Secp256k1 , VerifyOnly } ;
1036+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
9961037 use miniscript:: context:: NoChecks ;
9971038 use Miniscript ;
9981039 use MiniscriptKey ;
@@ -1005,15 +1046,21 @@ mod tests {
10051046 Vec < Vec < u8 > > ,
10061047 Vec < bitcoin:: EcdsaSig > ,
10071048 secp256k1:: Message ,
1008- Secp256k1 < VerifyOnly > ,
1049+ Secp256k1 < secp256k1:: All > ,
1050+ Vec < bitcoin:: XOnlyPublicKey > ,
1051+ Vec < bitcoin:: SchnorrSig > ,
1052+ Vec < Vec < u8 > > ,
10091053 ) {
1010- let secp_sign = secp256k1:: Secp256k1 :: signing_only ( ) ;
1011- let secp_verify = secp256k1:: Secp256k1 :: verification_only ( ) ;
1054+ let secp = secp256k1:: Secp256k1 :: new ( ) ;
10121055 let msg = secp256k1:: Message :: from_slice ( & b"Yoda: btc, I trust. HODL I must!" [ ..] )
10131056 . expect ( "32 bytes" ) ;
10141057 let mut pks = vec ! [ ] ;
10151058 let mut ecdsa_sigs = vec ! [ ] ;
10161059 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+
10171064 let mut sk = [ 0 ; 32 ] ;
10181065 for i in 1 ..n + 1 {
10191066 sk[ 0 ] = i as u8 ;
@@ -1022,10 +1069,10 @@ mod tests {
10221069
10231070 let sk = secp256k1:: SecretKey :: from_slice ( & sk[ ..] ) . expect ( "secret key" ) ;
10241071 let pk = bitcoin:: PublicKey {
1025- inner : secp256k1:: PublicKey :: from_secret_key ( & secp_sign , & sk) ,
1072+ inner : secp256k1:: PublicKey :: from_secret_key ( & secp , & sk) ,
10261073 compressed : true ,
10271074 } ;
1028- let sig = secp_sign . sign_ecdsa ( & msg, & sk) ;
1075+ let sig = secp . sign_ecdsa ( & msg, & sk) ;
10291076 ecdsa_sigs. push ( bitcoin:: EcdsaSig {
10301077 sig,
10311078 hash_ty : bitcoin:: EcdsaSigHashType :: All ,
@@ -1034,21 +1081,41 @@ mod tests {
10341081 sigser. push ( 0x01 ) ; // sighash_all
10351082 pks. push ( pk) ;
10361083 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) ;
10371094 }
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+ )
10391105 }
10401106
10411107 #[ test]
10421108 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 ) ;
10441111 let secp_ref = & secp;
10451112 let vfyfn_ = |pksig : & KeySigPair | match pksig {
10461113 KeySigPair :: Ecdsa ( pk, ecdsa_sig) => secp_ref
10471114 . verify_ecdsa ( & sighash, & ecdsa_sig. sig , & pk. inner )
10481115 . 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 ( ) ,
10521119 } ;
10531120
10541121 fn from_stack < ' txin , ' elem > (
@@ -1454,6 +1521,79 @@ mod tests {
14541521
14551522 let multi_error: Result < Vec < SatisfiedConstraint > , Error > = constraints. collect ( ) ;
14561523 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( ) ) ;
14571597 }
14581598
14591599 // By design there is no support for parse a miniscript with BitcoinKey
@@ -1463,4 +1603,10 @@ mod tests {
14631603 Miniscript :: from_str_insane ( ms) . unwrap ( ) ;
14641604 elem. to_no_checks_ms ( )
14651605 }
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+ }
14661612}
0 commit comments