1use std::fmt;
44
45use bitcoin;
46use elements::encode::{serialize, Encodable};
47use elements::hashes::{sha256d, Hash};
48use elements::{self, script, secp256k1_zkp, Script};
49
50use super::super::ELMTS_STR;
51use super::{CovError, CovOperations};
52use crate::descriptor::checksum::{self, verify_checksum};
53use crate::expression::{self, FromTree};
54use crate::extensions::ParseableExt;
55use crate::miniscript::lex::{lex, Token as Tk, TokenIter};
56use crate::miniscript::limits::{
57 MAX_OPS_PER_SCRIPT, MAX_SCRIPT_SIZE, MAX_STANDARD_P2WSH_SCRIPT_SIZE,
58};
59use crate::miniscript::{decode, types};
60use crate::util::varint_len;
61use crate::{
62 Error, ExtTranslator, Extension, ForEachKey, Miniscript, MiniscriptKey, Satisfier,
63 ScriptContext, Segwitv0, ToPublicKey, TranslateExt, TranslatePk, Translator,
64};
65
66fn hash256_arr<T: Encodable>(sl: &[T]) -> sha256d::Hash {
69 let mut enc = sha256d::Hash::engine();
70 for elem in sl {
71 elem.consensus_encode(&mut enc).unwrap();
72 }
73 sha256d::Hash::from_engine(enc)
74}
75pub(crate) const COV_SCRIPT_SIZE: usize = 120;
76pub(crate) const COV_SCRIPT_OPCODE_COST: usize = 74;
77#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
79pub struct LegacyCSFSCov<Pk: MiniscriptKey, Ext: Extension> {
80 pub(crate) pk: Pk,
83 pub(crate) ms: Miniscript<Pk, Segwitv0, Ext>,
87}
88
89impl<Pk: MiniscriptKey, Ext: Extension> LegacyCSFSCov<Pk, Ext> {
90 pub fn pk(&self) -> &Pk {
92 &self.pk
93 }
94
95 pub fn to_ms(&self) -> &Miniscript<Pk, Segwitv0, Ext> {
97 &self.ms
98 }
99
100 pub fn into_ms(self) -> Miniscript<Pk, Segwitv0, Ext> {
102 self.ms
103 }
104
105 pub fn new(pk: Pk, ms: Miniscript<Pk, Segwitv0, Ext>) -> Result<Self, Error> {
107 let ms_op_count = ms.ext.ops.op_count();
109 let cov_script_ops = COV_SCRIPT_OPCODE_COST;
112 let total_ops = ms_op_count.ok_or(Error::ImpossibleSatisfaction)? + cov_script_ops
113 - if ms.ext.has_free_verify { 1 } else { 0 };
114 if total_ops > MAX_OPS_PER_SCRIPT {
115 return Err(Error::ImpossibleSatisfaction);
116 }
117 let ss = COV_SCRIPT_SIZE - if ms.ext.has_free_verify { 1 } else { 0 };
121 if ms.script_size() + ss > MAX_SCRIPT_SIZE {
124 Err(Error::ScriptSizeTooLarge)
125 } else {
126 Ok(Self { pk, ms })
127 }
128 }
129 pub fn encode(&self) -> Script
131 where
132 Pk: ToPublicKey,
133 Ext: ParseableExt,
134 {
135 let builder = self.ms.node.encode(script::Builder::new());
136 builder.verify_cov(&self.pk.to_public_key()).into_script()
137 }
138
139 pub fn satisfy<S: Satisfier<Pk>>(&self, s: S, allow_mall: bool) -> Result<Vec<Vec<u8>>, Error>
141 where
142 Pk: ToPublicKey,
143 Ext: ParseableExt,
144 {
145 let mut wit = {
146 use crate::descriptor::CovError::MissingSighashItem;
147 let n_version = s.lookup_nversion().ok_or(MissingSighashItem(1))?;
148 let hash_prevouts = s.lookup_hashprevouts().ok_or(MissingSighashItem(1))?;
149 let hash_sequence = s.lookup_hashsequence().ok_or(MissingSighashItem(3))?;
150 let hash_issuances = s.lookup_hashissuances().ok_or(MissingSighashItem(3))?;
152 let outpoint = s.lookup_outpoint().ok_or(MissingSighashItem(4))?;
153 let script_code = s.lookup_scriptcode().ok_or(MissingSighashItem(5))?;
154 let value = s.lookup_value().ok_or(MissingSighashItem(6))?;
155 let n_sequence = s.lookup_nsequence().ok_or(MissingSighashItem(7))?;
156 let outputs = s.lookup_outputs().ok_or(MissingSighashItem(8))?;
157 let hash_outputs = hash256_arr(outputs);
158 let n_locktime = s.lookup_nlocktime().ok_or(MissingSighashItem(9))?;
159 let sighash_ty = s.lookup_sighashu32().ok_or(MissingSighashItem(10))?;
160
161 let (sig, hash_ty) = s
162 .lookup_ecdsa_sig(&self.pk)
163 .ok_or(CovError::MissingCovSignature)?;
164 if sighash_ty != hash_ty.as_u32() {
166 return Err(CovError::CovenantSighashTypeMismatch)?;
167 }
168
169 vec![
170 Vec::from(sig.serialize_der().as_ref()), serialize(&sighash_ty), serialize(&n_locktime), serialize(&hash_outputs), serialize(&n_sequence), serialize(&value), serialize(script_code), serialize(&outpoint), serialize(&hash_issuances), serialize(&hash_sequence), serialize(&hash_prevouts), serialize(&n_version), ]
183 };
184
185 let ms_wit = if !allow_mall {
186 self.ms.satisfy(s)?
187 } else {
188 self.ms.satisfy_malleable(s)?
189 };
190 wit.extend(ms_wit);
191 Ok(wit)
192 }
193
194 pub fn cov_script_code(&self) -> Script
198 where
199 Pk: ToPublicKey,
200 {
201 script::Builder::new().post_codesep_script().into_script()
202 }
203}
204
205impl<Ext: ParseableExt> LegacyCSFSCov<bitcoin::PublicKey, Ext> {
206 #[allow(unreachable_patterns)]
210 fn check_cov_script(tokens: &mut TokenIter<'_>) -> Result<bitcoin::PublicKey, Error> {
211 match_token!(tokens,
212 Tk::CheckSigFromStack, Tk::Verify, Tk::CheckSig, Tk::CodeSep, Tk::Swap,
213 Tk::FromAltStack, Tk::Dup, Tk::Bytes33(pk), Tk::Sha256,
214 Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(4), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(4), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(4), Tk::Size, Tk::Swap, Tk::Cat, Tk::EndIf,
219 Tk::Verify, Tk::Equal, Tk::Num(33), Tk::Size, Tk::Else,Tk::Verify, Tk::Equal, Tk::Num(9), Tk::Size, Tk::If, Tk::Equal, Tk::Num(1), Tk::Left, Tk::Num(1), Tk::Dup, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(3), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(36), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size, Tk::Swap, Tk::Cat, Tk::Verify, Tk::Equal, Tk::Num(32), Tk::Size, Tk::Swap, Tk::Verify, Tk::Equal, Tk::Num(4), Tk::Size, Tk::ToAltStack, Tk::Cat, Tk::Left, Tk::Num(1),
229 Tk::Pick, Tk::Num(11), Tk::Pick, Tk::Num(11), Tk::Verify => {
230 Ok(bitcoin::PublicKey::from_slice(pk)?)
231 },
232 _ => Err(Error::CovError(CovError::BadCovDescriptor)),
233 )
234 }
235
236 pub fn parse_insane(script: &script::Script) -> Result<Self, Error> {
244 let (pk, ms) = Self::parse_cov_components(script)?;
245 Self::new(pk, ms)
246 }
247
248 pub(crate) fn parse_cov_components(
253 script: &script::Script,
254 ) -> Result<
255 (
256 bitcoin::PublicKey,
257 Miniscript<bitcoin::PublicKey, Segwitv0, Ext>,
258 ),
259 Error,
260 >
261 where
262 Ext: ParseableExt,
263 {
264 let tokens = lex(script)?;
265 let mut iter = TokenIter::new(tokens);
266
267 let pk = LegacyCSFSCov::<bitcoin::PublicKey, Ext>::check_cov_script(&mut iter)?;
268 let ms = decode::parse(&mut iter)?;
269 Segwitv0::check_global_validity(&ms)?;
270 if ms.ty.corr.base != types::Base::B {
271 return Err(Error::NonTopLevel(format!("{:?}", ms)));
272 };
273 if let Some(leading) = iter.next() {
274 Err(Error::Trailing(leading.to_string()))
275 } else {
276 Ok((pk, ms))
277 }
278 }
279
280 pub fn parse(script: &script::Script) -> Result<Self, Error> {
284 let cov = Self::parse_insane(script)?;
285 cov.ms.sanity_check()?;
286 Ok(cov)
287 }
288}
289
290impl_from_tree!(
291 LegacyCSFSCov<Pk, Ext>,
292 => Ext; Extension,
293 fn from_tree(top: &expression::Tree<'_>) -> Result<Self, Error> {
294 if top.name == "elcovwsh" && top.args.len() == 2 {
295 let pk = expression::terminal(&top.args[0], |pk| Pk::from_str(pk))?;
296 let top = &top.args[1];
297 let sub = Miniscript::from_tree(top)?;
298 Segwitv0::top_level_checks(&sub)?;
299 Ok(LegacyCSFSCov { pk, ms: sub })
300 } else {
301 Err(Error::Unexpected(format!(
302 "{}({} args) while parsing elcovwsh descriptor",
303 top.name,
304 top.args.len(),
305 )))
306 }
307 }
308);
309impl<Pk, Ext> fmt::Debug for LegacyCSFSCov<Pk, Ext>
310where
311 Pk: MiniscriptKey,
312 Ext: Extension,
313{
314 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315 write!(f, "{}covwsh({},{})", ELMTS_STR, self.pk, self.ms)
316 }
317}
318
319impl<Pk, Ext> fmt::Display for LegacyCSFSCov<Pk, Ext>
320where
321 Pk: MiniscriptKey,
322 Ext: Extension,
323{
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 use fmt::Write;
326 let mut wrapped_f = checksum::Formatter::new(f);
327 write!(wrapped_f, "{}covwsh({},{})", ELMTS_STR, self.pk, self.ms)?;
328 wrapped_f.write_checksum_if_not_alt()
329 }
330}
331
332impl_from_str!(
333 LegacyCSFSCov<Pk, Ext>,
334 => Ext; Extension,
335 type Err = Error;,
336
337 fn from_str(s: &str) -> Result<Self, Self::Err> {
338 let desc_str = verify_checksum(s)?;
339 let top = expression::Tree::from_str(desc_str)?;
340 LegacyCSFSCov::<Pk, Ext>::from_tree(&top)
341 }
342);
343
344impl<Pk, Ext> LegacyCSFSCov<Pk, Ext>
345where
346 Pk: MiniscriptKey,
347 Ext: Extension,
348{
349 pub fn sanity_check(&self) -> Result<(), Error> {
351 self.ms.sanity_check()?;
352 let ss = COV_SCRIPT_SIZE - if self.ms.ext.has_free_verify { 1 } else { 0 };
354 if self.ms.script_size() + ss > MAX_STANDARD_P2WSH_SCRIPT_SIZE {
355 Err(Error::ScriptSizeTooLarge)
356 } else {
357 Ok(())
358 }
359 }
360
361 pub fn address(
363 &self,
364 blinder: Option<secp256k1_zkp::PublicKey>,
365 params: &'static elements::AddressParams,
366 ) -> elements::Address
367 where
368 Pk: ToPublicKey,
369 Ext: ParseableExt,
370 {
371 elements::Address::p2wsh(&self.encode(), blinder, params)
372 }
373
374 pub fn script_pubkey(&self) -> Script
376 where
377 Pk: ToPublicKey,
378 Ext: ParseableExt,
379 {
380 self.encode().to_v0_p2wsh()
381 }
382
383 pub fn unsigned_script_sig(&self) -> Script
386 where
387 Pk: ToPublicKey,
388 {
389 Script::new()
390 }
391
392 pub fn inner_script(&self) -> Script
394 where
395 Pk: ToPublicKey,
396 Ext: ParseableExt,
397 {
398 self.encode()
399 }
400
401 pub fn get_satisfaction<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
405 where
406 Pk: ToPublicKey,
407 S: Satisfier<Pk>,
408 Ext: ParseableExt,
409 {
410 let mut witness = self.satisfy(satisfier, false)?;
411 witness.push(self.encode().into_bytes());
412 let script_sig = Script::new();
413 Ok((witness, script_sig))
414 }
415
416 pub fn max_satisfaction_weight(&self) -> Result<usize, Error> {
419 let script_size =
420 self.ms.script_size() + 58 - if self.ms.ext.has_free_verify { 1 } else { 0 };
421 let max_sat_elems = self.ms.max_satisfaction_witness_elements()? + 12;
422 let max_sat_size = self.ms.max_satisfaction_size()? + 275;
423
424 Ok(4 + varint_len(script_size) +
426 script_size +
427 varint_len(max_sat_elems) +
428 max_sat_size)
429 }
430
431 pub fn ecdsa_sighash_script_code(&self) -> Script
436 where
437 Pk: ToPublicKey,
438 Ext: ParseableExt,
439 {
440 self.inner_script()
441 }
442
443 pub fn get_satisfaction_mall<S>(&self, satisfier: S) -> Result<(Vec<Vec<u8>>, Script), Error>
447 where
448 Pk: ToPublicKey,
449 S: Satisfier<Pk>,
450 Ext: ParseableExt,
451 {
452 let mut witness = self.satisfy(satisfier, true)?;
453 witness.push(self.encode().into_bytes());
454 let script_sig = Script::new();
455 Ok((witness, script_sig))
456 }
457}
458
459impl<Pk: MiniscriptKey, Ext: Extension> ForEachKey<Pk> for LegacyCSFSCov<Pk, Ext> {
460 fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool
461 where
462 Pk: 'a,
463 {
464 pred(&self.pk) && self.ms.for_any_key(pred)
465 }
466}
467
468impl<P, Q, Ext> TranslatePk<P, Q> for LegacyCSFSCov<P, Ext>
469where
470 P: MiniscriptKey,
471 Q: MiniscriptKey,
472 Ext: Extension,
473{
474 type Output = LegacyCSFSCov<Q, Ext>;
475
476 fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
477 where
478 T: Translator<P, Q, E>,
479 {
480 Ok(LegacyCSFSCov {
481 pk: t.pk(&self.pk)?,
482 ms: self.ms.translate_pk(t)?,
483 })
484 }
485}
486
487impl<Pk, Ext, ExtQ> TranslateExt<Ext, ExtQ> for LegacyCSFSCov<Pk, Ext>
488where
489 Pk: MiniscriptKey,
490 Ext: Extension,
491 ExtQ: Extension,
492 Ext: TranslateExt<Ext, ExtQ, Output = ExtQ>,
493{
494 type Output = LegacyCSFSCov<Pk, ExtQ>;
495
496 fn translate_ext<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
497 where
498 T: ExtTranslator<Ext, ExtQ, E>,
499 {
500 Ok(LegacyCSFSCov {
501 pk: self.pk.clone(),
502 ms: self.ms.translate_ext(translator)?,
503 })
504 }
505}