Skip to content

Commit 1d32003

Browse files
committed
Merge commit 'bc2d097'
bc2d097 Merge rust-bitcoin/rust-miniscript#308: MultiA interpreter
2 parents a9661f3 + bc2d097 commit 1d32003

File tree

1 file changed

+158
-11
lines changed

1 file changed

+158
-11
lines changed

src/interpreter/mod.rs

Lines changed: 158 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,47 @@ where
952952
None => return Some(Err(Error::UnexpectedStackEnd)),
953953
}
954954
}
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+
}
955996
Terminal::Multi(ref k, ref subs) if node_state.n_evaluated == 0 => {
956997
let len = self.stack.len();
957998
if len < k + 1 {
@@ -1162,7 +1203,7 @@ mod tests {
11621203
use super::*;
11631204
use bitcoin;
11641205
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
1165-
use elements::secp256k1_zkp::{Secp256k1, VerifyOnly};
1206+
use elements::secp256k1_zkp::{self, Secp256k1};
11661207
use miniscript::context::NoChecks;
11671208
use ElementsSig;
11681209
use Miniscript;
@@ -1177,15 +1218,21 @@ mod tests {
11771218
Vec<Vec<u8>>,
11781219
Vec<ElementsSig>,
11791220
secp256k1_zkp::Message,
1180-
Secp256k1<VerifyOnly>,
1221+
Secp256k1<secp256k1_zkp::All>,
1222+
Vec<bitcoin::XOnlyPublicKey>,
1223+
Vec<elements::SchnorrSig>,
1224+
Vec<Vec<u8>>,
11811225
) {
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();
11841227
let msg = secp256k1_zkp::Message::from_slice(&b"Yoda: btc, I trust. HODL I must!"[..])
11851228
.expect("32 bytes");
11861229
let mut pks = vec![];
11871230
let mut ecdsa_sigs = vec![];
11881231
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+
11891236
let mut sk = [0; 32];
11901237
for i in 1..n + 1 {
11911238
sk[0] = i as u8;
@@ -1194,30 +1241,50 @@ mod tests {
11941241

11951242
let sk = secp256k1_zkp::SecretKey::from_slice(&sk[..]).expect("secret key");
11961243
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),
11981245
compressed: true,
11991246
};
1200-
let sig = secp_sign.sign_ecdsa(&msg, &sk);
1247+
let sig = secp.sign_ecdsa(&msg, &sk);
12011248
ecdsa_sigs.push((sig, elements::SigHashType::All));
12021249
let mut sigser = sig.serialize_der().to_vec();
12031250
sigser.push(0x01); // sighash_all
12041251
pks.push(pk);
12051252
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);
12061263
}
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+
)
12081274
}
12091275

12101276
#[test]
12111277
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);
12131280
let secp_ref = &secp;
12141281
let vfyfn_ = |pksig: &KeySigPair| match pksig {
12151282
KeySigPair::Ecdsa(pk, ecdsa_sig) => secp_ref
12161283
.verify_ecdsa(&sighash, &ecdsa_sig.0, &pk.inner)
12171284
.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(),
12211288
};
12221289

12231290
fn from_stack<'txin, 'elem>(
@@ -1634,6 +1701,80 @@ mod tests {
16341701

16351702
let multi_error: Result<Vec<SatisfiedConstraint<NoExt>>, Error> = constraints.collect();
16361703
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());
16371778
}
16381779

16391780
// By design there is no support for parse a miniscript with BitcoinKey
@@ -1643,4 +1784,10 @@ mod tests {
16431784
Miniscript::from_str_insane(ms).unwrap();
16441785
elem.to_no_checks_ms()
16451786
}
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+
}
16461793
}

0 commit comments

Comments
 (0)