@@ -952,6 +952,47 @@ where
952
952
None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
953
953
}
954
954
}
955
+ Terminal :: MultiA ( k, ref subs) => {
956
+ if node_state. n_evaluated == subs. len ( ) {
957
+ if node_state. n_satisfied == k {
958
+ self . stack . push ( stack:: Element :: Satisfied ) ;
959
+ } else {
960
+ self . stack . push ( stack:: Element :: Dissatisfied ) ;
961
+ }
962
+ } else {
963
+ // evaluate each key with as a pk
964
+ // note that evaluate_pk will error on non-empty incorrect sigs
965
+ // push 1 on satisfied sigs and push 0 on empty sigs
966
+ match self
967
+ . stack
968
+ . evaluate_pk ( & mut self . verify_sig , & subs[ node_state. n_evaluated ] )
969
+ {
970
+ Some ( Ok ( x) ) => {
971
+ self . push_evaluation_state (
972
+ node_state. node ,
973
+ node_state. n_evaluated + 1 ,
974
+ node_state. n_satisfied + 1 ,
975
+ ) ;
976
+ match self . stack . pop ( ) {
977
+ Some ( ..) => return Some ( Ok ( x) ) ,
978
+ None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
979
+ }
980
+ }
981
+ None => {
982
+ self . push_evaluation_state (
983
+ node_state. node ,
984
+ node_state. n_evaluated + 1 ,
985
+ node_state. n_satisfied ,
986
+ ) ;
987
+ match self . stack . pop ( ) {
988
+ Some ( ..) => { } // not-satisfied, look for next key
989
+ None => return Some ( Err ( Error :: UnexpectedStackEnd ) ) ,
990
+ }
991
+ }
992
+ x => return x, //forward errors as is
993
+ }
994
+ }
995
+ }
955
996
Terminal :: Multi ( ref k, ref subs) if node_state. n_evaluated == 0 => {
956
997
let len = self . stack . len ( ) ;
957
998
if len < k + 1 {
@@ -1162,7 +1203,7 @@ mod tests {
1162
1203
use super :: * ;
1163
1204
use bitcoin;
1164
1205
use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d, Hash } ;
1165
- use elements:: secp256k1_zkp:: { Secp256k1 , VerifyOnly } ;
1206
+ use elements:: secp256k1_zkp:: { self , Secp256k1 } ;
1166
1207
use miniscript:: context:: NoChecks ;
1167
1208
use ElementsSig ;
1168
1209
use Miniscript ;
@@ -1177,15 +1218,21 @@ mod tests {
1177
1218
Vec < Vec < u8 > > ,
1178
1219
Vec < ElementsSig > ,
1179
1220
secp256k1_zkp:: Message ,
1180
- Secp256k1 < VerifyOnly > ,
1221
+ Secp256k1 < secp256k1_zkp:: All > ,
1222
+ Vec < bitcoin:: XOnlyPublicKey > ,
1223
+ Vec < elements:: SchnorrSig > ,
1224
+ Vec < Vec < u8 > > ,
1181
1225
) {
1182
- let secp_sign = secp256k1_zkp:: Secp256k1 :: signing_only ( ) ;
1183
- let secp_verify = secp256k1_zkp:: Secp256k1 :: verification_only ( ) ;
1226
+ let secp = secp256k1_zkp:: Secp256k1 :: new ( ) ;
1184
1227
let msg = secp256k1_zkp:: Message :: from_slice ( & b"Yoda: btc, I trust. HODL I must!" [ ..] )
1185
1228
. expect ( "32 bytes" ) ;
1186
1229
let mut pks = vec ! [ ] ;
1187
1230
let mut ecdsa_sigs = vec ! [ ] ;
1188
1231
let mut der_sigs = vec ! [ ] ;
1232
+ let mut x_only_pks = vec ! [ ] ;
1233
+ let mut schnorr_sigs = vec ! [ ] ;
1234
+ let mut ser_schnorr_sigs = vec ! [ ] ;
1235
+
1189
1236
let mut sk = [ 0 ; 32 ] ;
1190
1237
for i in 1 ..n + 1 {
1191
1238
sk[ 0 ] = i as u8 ;
@@ -1194,30 +1241,50 @@ mod tests {
1194
1241
1195
1242
let sk = secp256k1_zkp:: SecretKey :: from_slice ( & sk[ ..] ) . expect ( "secret key" ) ;
1196
1243
let pk = bitcoin:: PublicKey {
1197
- inner : secp256k1_zkp:: PublicKey :: from_secret_key ( & secp_sign , & sk) ,
1244
+ inner : secp256k1_zkp:: PublicKey :: from_secret_key ( & secp , & sk) ,
1198
1245
compressed : true ,
1199
1246
} ;
1200
- let sig = secp_sign . sign_ecdsa ( & msg, & sk) ;
1247
+ let sig = secp . sign_ecdsa ( & msg, & sk) ;
1201
1248
ecdsa_sigs. push ( ( sig, elements:: SigHashType :: All ) ) ;
1202
1249
let mut sigser = sig. serialize_der ( ) . to_vec ( ) ;
1203
1250
sigser. push ( 0x01 ) ; // sighash_all
1204
1251
pks. push ( pk) ;
1205
1252
der_sigs. push ( sigser) ;
1253
+
1254
+ let keypair = bitcoin:: KeyPair :: from_secret_key ( & secp, sk) ;
1255
+ x_only_pks. push ( bitcoin:: XOnlyPublicKey :: from_keypair ( & keypair) ) ;
1256
+ let schnorr_sig = secp. sign_schnorr_with_aux_rand ( & msg, & keypair, & [ 0u8 ; 32 ] ) ;
1257
+ let schnorr_sig = elements:: SchnorrSig {
1258
+ sig : schnorr_sig,
1259
+ hash_ty : elements:: SchnorrSigHashType :: Default ,
1260
+ } ;
1261
+ ser_schnorr_sigs. push ( schnorr_sig. to_vec ( ) ) ;
1262
+ schnorr_sigs. push ( schnorr_sig) ;
1206
1263
}
1207
- ( pks, der_sigs, ecdsa_sigs, msg, secp_verify)
1264
+ (
1265
+ pks,
1266
+ der_sigs,
1267
+ ecdsa_sigs,
1268
+ msg,
1269
+ secp,
1270
+ x_only_pks,
1271
+ schnorr_sigs,
1272
+ ser_schnorr_sigs,
1273
+ )
1208
1274
}
1209
1275
1210
1276
#[ test]
1211
1277
fn sat_constraints ( ) {
1212
- let ( pks, der_sigs, ecdsa_sigs, sighash, secp) = setup_keys_sigs ( 10 ) ;
1278
+ let ( pks, der_sigs, ecdsa_sigs, sighash, secp, xpks, schnorr_sigs, ser_schnorr_sigs) =
1279
+ setup_keys_sigs ( 10 ) ;
1213
1280
let secp_ref = & secp;
1214
1281
let vfyfn_ = |pksig : & KeySigPair | match pksig {
1215
1282
KeySigPair :: Ecdsa ( pk, ecdsa_sig) => secp_ref
1216
1283
. verify_ecdsa ( & sighash, & ecdsa_sig. 0 , & pk. inner )
1217
1284
. is_ok ( ) ,
1218
- KeySigPair :: Schnorr ( _xpk , _schnorr_sig ) => {
1219
- unreachable ! ( "Schnorr sig not tested in this test" )
1220
- }
1285
+ KeySigPair :: Schnorr ( xpk , schnorr_sig ) => secp_ref
1286
+ . verify_schnorr ( & schnorr_sig . sig , & sighash , xpk )
1287
+ . is_ok ( ) ,
1221
1288
} ;
1222
1289
1223
1290
fn from_stack < ' txin , ' elem > (
@@ -1634,6 +1701,80 @@ mod tests {
1634
1701
1635
1702
let multi_error: Result < Vec < SatisfiedConstraint < NoExt > > , Error > = constraints. collect ( ) ;
1636
1703
assert ! ( multi_error. is_err( ) ) ;
1704
+
1705
+ // multi_a tests
1706
+ let stack = Stack :: from ( vec ! [
1707
+ stack:: Element :: Dissatisfied ,
1708
+ stack:: Element :: Dissatisfied ,
1709
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 2 ] ) ,
1710
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 1 ] ) ,
1711
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 0 ] ) ,
1712
+ ] ) ;
1713
+
1714
+ let elem = x_only_no_checks_ms ( & format ! (
1715
+ "multi_a(3,{},{},{},{},{})" ,
1716
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1717
+ ) ) ;
1718
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1719
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack, & elem) ;
1720
+
1721
+ let multi_a_satisfied: Result < Vec < SatisfiedConstraint < NoExt > > , Error > =
1722
+ constraints. collect ( ) ;
1723
+ assert_eq ! (
1724
+ multi_a_satisfied. unwrap( ) ,
1725
+ vec![
1726
+ SatisfiedConstraint :: PublicKey {
1727
+ key_sig: KeySigPair :: Schnorr ( xpks[ 0 ] , schnorr_sigs[ 0 ] )
1728
+ } ,
1729
+ SatisfiedConstraint :: PublicKey {
1730
+ key_sig: KeySigPair :: Schnorr ( xpks[ 1 ] , schnorr_sigs[ 1 ] )
1731
+ } ,
1732
+ SatisfiedConstraint :: PublicKey {
1733
+ key_sig: KeySigPair :: Schnorr ( xpks[ 2 ] , schnorr_sigs[ 2 ] )
1734
+ } ,
1735
+ ]
1736
+ ) ;
1737
+
1738
+ // multi_a tests: wrong order of sigs
1739
+ let stack = Stack :: from ( vec ! [
1740
+ stack:: Element :: Dissatisfied ,
1741
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 2 ] ) ,
1742
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 1 ] ) ,
1743
+ stack:: Element :: Push ( & ser_schnorr_sigs[ 0 ] ) ,
1744
+ stack:: Element :: Dissatisfied ,
1745
+ ] ) ;
1746
+
1747
+ let elem = x_only_no_checks_ms ( & format ! (
1748
+ "multi_a(3,{},{},{},{},{})" ,
1749
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1750
+ ) ) ;
1751
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1752
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack. clone ( ) , & elem) ;
1753
+
1754
+ let multi_a_error: Result < Vec < SatisfiedConstraint < NoExt > > , Error > = constraints. collect ( ) ;
1755
+ assert ! ( multi_a_error. is_err( ) ) ;
1756
+
1757
+ // multi_a wrong thresh: k = 2, but three sigs
1758
+ let elem = x_only_no_checks_ms ( & format ! (
1759
+ "multi_a(2,{},{},{},{},{})" ,
1760
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] ,
1761
+ ) ) ;
1762
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1763
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack. clone ( ) , & elem) ;
1764
+
1765
+ let multi_a_error: Result < Vec < SatisfiedConstraint < NoExt > > , Error > = constraints. collect ( ) ;
1766
+ assert ! ( multi_a_error. is_err( ) ) ;
1767
+
1768
+ // multi_a correct thresh, but small stack
1769
+ let elem = x_only_no_checks_ms ( & format ! (
1770
+ "multi_a(3,{},{},{},{},{},{})" ,
1771
+ xpks[ 0 ] , xpks[ 1 ] , xpks[ 2 ] , xpks[ 3 ] , xpks[ 4 ] , xpks[ 5 ]
1772
+ ) ) ;
1773
+ let vfyfn = vfyfn_. clone ( ) ; // sigh rust 1.29...
1774
+ let constraints = from_stack ( Box :: new ( vfyfn) , stack, & elem) ;
1775
+
1776
+ let multi_a_error: Result < Vec < SatisfiedConstraint < NoExt > > , Error > = constraints. collect ( ) ;
1777
+ assert ! ( multi_a_error. is_err( ) ) ;
1637
1778
}
1638
1779
1639
1780
// By design there is no support for parse a miniscript with BitcoinKey
@@ -1643,4 +1784,10 @@ mod tests {
1643
1784
Miniscript :: from_str_insane ( ms) . unwrap ( ) ;
1644
1785
elem. to_no_checks_ms ( )
1645
1786
}
1787
+
1788
+ fn x_only_no_checks_ms ( ms : & str ) -> Miniscript < BitcoinKey , NoChecks > {
1789
+ let elem: Miniscript < bitcoin:: XOnlyPublicKey , NoChecks > =
1790
+ Miniscript :: from_str_insane ( ms) . unwrap ( ) ;
1791
+ elem. to_no_checks_ms ( )
1792
+ }
1646
1793
}
0 commit comments