1use core::convert::TryFrom;
4
5use bitcoin::hashes::Hash;
6use bitcoin::script::{self, PushBytes, ScriptBuf};
7use bitcoin::PubkeyHash;
8
9use crate::miniscript::context;
10use crate::miniscript::satisfy::Placeholder;
11use crate::prelude::*;
12use crate::{MiniscriptKey, ScriptContext, ToPublicKey};
13pub(crate) fn varint_len(n: usize) -> usize { bitcoin::VarInt(n as u64).size() }
14
15pub(crate) trait ItemSize {
16 fn size(&self) -> usize;
17}
18
19impl<Pk: MiniscriptKey> ItemSize for Placeholder<Pk> {
20 fn size(&self) -> usize {
21 match self {
22 Placeholder::Pubkey(_, size) => *size,
23 Placeholder::PubkeyHash(_, size) => *size,
24 Placeholder::EcdsaSigPk(_) | Placeholder::EcdsaSigPkHash(_) => 73,
25 Placeholder::SchnorrSigPk(_, _, size) | Placeholder::SchnorrSigPkHash(_, _, size) => {
26 size + 1
27 } Placeholder::HashDissatisfaction
29 | Placeholder::Sha256Preimage(_)
30 | Placeholder::Hash256Preimage(_)
31 | Placeholder::Ripemd160Preimage(_)
32 | Placeholder::Hash160Preimage(_) => 33,
33 Placeholder::PushOne => 2, Placeholder::PushZero => 1,
35 Placeholder::TapScript(s) => s.len(),
36 Placeholder::TapControlBlock(cb) => cb.serialize().len(),
37 }
38 }
39}
40
41impl ItemSize for Vec<u8> {
42 fn size(&self) -> usize { self.len() }
43}
44
45pub(crate) fn witness_size<T: ItemSize>(wit: &[T]) -> usize {
47 wit.iter().map(T::size).sum::<usize>() + varint_len(wit.len())
48}
49
50pub(crate) fn witness_to_scriptsig(witness: &[Vec<u8>]) -> ScriptBuf {
51 let mut b = script::Builder::new();
52 for wit in witness {
53 if let Ok(n) = script::read_scriptint(wit) {
54 b = b.push_int(n);
55 } else {
56 let push = <&PushBytes>::try_from(wit.as_slice())
57 .expect("All pushes in miniscript are <73 bytes");
58 b = b.push_slice(push)
59 }
60 }
61 b.into_script()
62}
63
64pub(crate) trait MsKeyBuilder {
66 fn push_ms_key<Pk, Ctx>(self, key: &Pk) -> Self
68 where
69 Pk: ToPublicKey,
70 Ctx: ScriptContext;
71
72 fn push_ms_key_hash<Pk, Ctx>(self, key: &Pk) -> Self
74 where
75 Pk: ToPublicKey,
76 Ctx: ScriptContext;
77}
78
79impl MsKeyBuilder for script::Builder {
80 fn push_ms_key<Pk, Ctx>(self, key: &Pk) -> Self
81 where
82 Pk: ToPublicKey,
83 Ctx: ScriptContext,
84 {
85 match Ctx::sig_type() {
86 context::SigType::Ecdsa => self.push_key(&key.to_public_key()),
87 context::SigType::Schnorr => self.push_slice(key.to_x_only_pubkey().serialize()),
88 }
89 }
90
91 fn push_ms_key_hash<Pk, Ctx>(self, key: &Pk) -> Self
92 where
93 Pk: ToPublicKey,
94 Ctx: ScriptContext,
95 {
96 match Ctx::sig_type() {
97 context::SigType::Ecdsa => self.push_slice(key.to_public_key().pubkey_hash()),
98 context::SigType::Schnorr => {
99 self.push_slice(PubkeyHash::hash(&key.to_x_only_pubkey().serialize()))
100 }
101 }
102 }
103}