Skip to content

Commit bc2d097

Browse files
committed
Merge #308: MultiA interpreter
251921e Add some multi_a interpreter tests (sanket1729) f711901 MultiA interpreter (sanket1729) Pull request description: Support for multi_a interpreter. Required for interpreter check finalizer. ACKs for top commit: dr-orlovsky: utACK 251921e apoelstra: ACK 251921e Tree-SHA512: f6d972bd1d879d3cd8b66caaff2bcd69d766bb2c93238e42e5bb379cffc395a4cc219d71666b020ffde25e5d589e3070b8cc089a0ef4cd72da6335955d4d14c1
2 parents f26bf42 + 251921e commit bc2d097

File tree

1 file changed

+157
-11
lines changed

1 file changed

+157
-11
lines changed

src/interpreter/mod.rs

Lines changed: 157 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)