1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
// Miniscript
// Written in 2020 by
// Rust Elements developers
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//! DynaFed Pegin Descriptor Support
//!
//! Traits and implementations for Dynafed Pegin descriptors.
//! Note that this is a bitcoin descriptor and thus cannot be
//! added to elements Descriptor.
//! Unlike Pegin descriptors these are Miniscript, so dealing
//! with these is easier.
use std::convert::TryFrom;
use std::fmt;
use bitcoin::blockdata::script::{self, PushBytes};
use bitcoin::hashes::Hash;
use bitcoin::{self, hashes, ScriptBuf as BtcScript};
use elements::secp256k1_zkp;
use crate::descriptor::checksum::{desc_checksum, verify_checksum};
use crate::expression::{self, FromTree};
use crate::extensions::{CovExtArgs, CovenantExt};
use crate::policy::{semantic, Liftable};
use crate::{
BtcDescriptor, BtcError, BtcFromTree, BtcLiftable, BtcPolicy, BtcSatisfier, BtcTree,
Descriptor, Error, MiniscriptKey, ToPublicKey,
};
/// New Pegin Descriptor with Miniscript support
/// Useful with dynamic federations
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Pegin<Pk: MiniscriptKey> {
/// The untweaked pegin bitcoin descriptor
pub fed_desc: BtcDescriptor<Pk>,
/// The redeem elements descriptor
///
/// TODO: Allow pegin redeem descriptor with extensions
pub elem_desc: Descriptor<Pk, CovenantExt<CovExtArgs>>,
}
impl<Pk: MiniscriptKey> Pegin<Pk> {
/// Create a new LegacyPegin descriptor
pub fn new(
fed_desc: BtcDescriptor<Pk>,
elem_desc: Descriptor<Pk, CovenantExt<CovExtArgs>>,
) -> Self {
Self {
fed_desc,
elem_desc,
}
}
}
impl<Pk: MiniscriptKey> fmt::Debug for Pegin<Pk> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "pegin({:?},{:?})", self.fed_desc, self.elem_desc)
}
}
impl<Pk: MiniscriptKey> fmt::Display for Pegin<Pk> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let desc = format!("pegin({},{})", self.fed_desc, self.elem_desc);
let checksum = desc_checksum(&desc).map_err(|_| fmt::Error)?;
write!(f, "{}#{}", &desc, &checksum)
}
}
impl<Pk: MiniscriptKey> Liftable<Pk> for Pegin<Pk> {
fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
let btc_pol = BtcLiftable::lift(&self.fed_desc)?;
Liftable::lift(&btc_pol)
}
}
impl<Pk: MiniscriptKey> BtcLiftable<Pk> for Pegin<Pk> {
fn lift(&self) -> Result<BtcPolicy<Pk>, BtcError> {
self.fed_desc.lift()
}
}
impl_from_tree!(
Pegin<Pk>,
fn from_tree(top: &expression::Tree<'_>) -> Result<Self, Error> {
if top.name == "pegin" && top.args.len() == 2 {
// a roundtrip hack to use FromTree from bitcoin::Miniscript from
// expression::Tree in elements.
let ms_str = top.args[0].to_string();
let ms_expr = BtcTree::from_str(&ms_str)?;
//
// TODO: Confirm with Andrew about the descriptor type for dynafed
// Assuming sh(wsh) for now.
let fed_desc = BtcDescriptor::<Pk>::from_tree(&ms_expr)?;
let elem_desc = Descriptor::<Pk, CovenantExt<CovExtArgs>>::from_tree(&top.args[1])?;
Ok(Pegin::new(fed_desc, elem_desc))
} else {
Err(Error::Unexpected(format!(
"{}({} args) while parsing legacy_pegin descriptor",
top.name,
top.args.len(),
)))
}
}
);
impl_from_str!(
Pegin<Pk>,
type Err = Error;,
fn from_str(s: &str) -> Result<Self, Self::Err> {
let desc_str = verify_checksum(s)?;
let top = expression::Tree::from_str(desc_str)?;
Self::from_tree(&top)
}
);
impl<Pk: MiniscriptKey> Pegin<Pk> {
/// Checks whether the descriptor is safe.
pub fn sanity_check(&self) -> Result<(), Error> {
self.fed_desc
.sanity_check()
.map_err(|_| Error::Unexpected("Federation script sanity check failed".to_string()))?;
self.elem_desc
.sanity_check()
.map_err(|_| Error::Unexpected("Federation script sanity check failed".to_string()))?;
Ok(())
}
/// Computes the Bitcoin address of the pegin descriptor, if one exists.
/// Requires the secp context to compute the tweak
pub fn bitcoin_address<C: secp256k1_zkp::Verification>(
&self,
network: bitcoin::Network,
secp: &secp256k1_zkp::Secp256k1<C>,
) -> Result<bitcoin::Address, Error>
where
Pk: ToPublicKey,
{
// TODO
Ok(bitcoin::Address::p2shwsh(
&self
.bitcoin_witness_script(secp)
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
network,
))
}
/// Computes the bitcoin scriptpubkey of the descriptor.
/// Requires the secp context to compute the tweak
pub fn bitcoin_script_pubkey<C: secp256k1_zkp::Verification>(
&self,
secp: &secp256k1_zkp::Secp256k1<C>,
) -> BtcScript
where
Pk: ToPublicKey,
{
self.bitcoin_address(bitcoin::Network::Bitcoin, secp)
.expect("Address cannot fail for pegin")
.script_pubkey()
}
/// Computes the scriptSig that will be in place for an unsigned
/// input spending an output with this descriptor. For pre-segwit
/// descriptors, which use the scriptSig for signatures, this
/// returns the empty script.
///
/// This is used in Segwit transactions to produce an unsigned
/// transaction whose txid will not change during signing (since
/// only the witness data will change).
/// Requires the secp context to compute the tweak
pub fn bitcoin_unsigned_script_sig<C: secp256k1_zkp::Verification>(
&self,
secp: &secp256k1_zkp::Secp256k1<C>,
) -> BtcScript
where
Pk: ToPublicKey,
{
let witness_script = self
.bitcoin_witness_script(secp)
.expect("TODO after taproot");
let push_bytes = <&PushBytes>::try_from(witness_script.as_bytes())
.expect("Witness script is not too larg");
script::Builder::new().push_slice(push_bytes).into_script()
}
/// Computes the bitcoin "witness script" of the descriptor, i.e. the underlying
/// script before any hashing is done. For `Bare`, `Pkh` and `Wpkh` this
/// is the scriptPubkey; for `ShWpkh` and `Sh` this is the redeemScript;
/// for the others it is the witness script.
pub fn bitcoin_witness_script<C: secp256k1_zkp::Verification>(
&self,
_secp: &secp256k1_zkp::Secp256k1<C>,
) -> Result<BtcScript, Error>
where
Pk: ToPublicKey,
{
let tweak_vec = self
.elem_desc
.explicit_script()
.expect("Tr pegins unknown yet")
.into_bytes();
let _tweak = hashes::sha256::Hash::hash(&tweak_vec);
unreachable!("TODO: After upstream Refactor for Translator trait")
// let derived = self.fed_desc.derive
// struct TranslateTweak<'a, C: secp256k1_zkp::Verification>(
// hashes::sha256::Hash,
// &'a secp256k1_zkp::Secp256k1<C>,
// );
// impl<'a, Pk, C> PkTranslator<Pk, bitcoin::PublicKey, ()> for TranslateTweak<'a, C>
// where
// Pk: MiniscriptKey,
// C: secp256k1_zkp::Verification,
// {
// fn pk(&mut self, pk: &Pk) -> Result<bitcoin::PublicKey, ()> {
// tweak_key(pk, self.1, self.0.as_inner())
// }
// fn pkh(
// &mut self,
// pkh: &<Pk as MiniscriptKey>::Hash,
// ) -> Result<<bitcoin::PublicKey as MiniscriptKey>::Hash, ()> {
// unreachable!("No keyhashes in elements descriptors")
// }
// }
// let mut t = TranslateTweak(tweak, secp);
// let tweaked_desc = <bitcoin_miniscript::TranslatePk>::translate_pk(&self.fed_desc, t).expect("Tweaking must succeed"),
// Ok(tweaked_desc.explicit_script()?)
}
/// Returns satisfying witness and scriptSig to spend an
/// output controlled by the given descriptor if it possible to
/// construct one using the satisfier S.
pub fn get_bitcoin_satisfaction<S, C: secp256k1_zkp::Verification>(
&self,
_secp: &secp256k1_zkp::Secp256k1<C>,
_satisfier: S,
) -> Result<(Vec<Vec<u8>>, BtcScript), Error>
where
S: BtcSatisfier<bitcoin::PublicKey>,
Pk: ToPublicKey,
{
let tweak_vec = self
.elem_desc
.explicit_script()
.expect("Tr pegins unknown yet")
.into_bytes();
let _tweak = hashes::sha256::Hash::hash(&tweak_vec);
unreachable!("TODO: After upstream refactor");
// let tweaked_desc = self.fed_desc.translate_pk_infallible(
// |pk| tweak_key(pk, secp, tweak.as_inner()),
// |_| unreachable!("No keyhashes in elements descriptors"),
// );
// let res = tweaked_desc.get_satisfaction(satisfier)?;
// Ok(res)
}
/// Computes an upper bound on the weight of a satisfying witness to the
/// transaction. Assumes all signatures are 73 bytes, including push opcode
/// and sighash suffix. Includes the weight of the VarInts encoding the
/// scriptSig and witness stack length.
// FIXME: the ToPublicKey bound here should not needed. Fix after upstream
pub fn max_satisfaction_weight(&self) -> Result<usize, Error>
where
Pk: ToPublicKey,
{
// tweaking does not change max satisfaction weight
let w = self.fed_desc.max_weight_to_satisfy()?;
Ok(w)
}
/// Get the `scriptCode` of a transaction output.
///
/// The `scriptCode` is the Script of the previous transaction output being serialized in the
/// sighash when evaluating a `CHECKSIG` & co. OP code.
pub fn script_code<C: secp256k1_zkp::Verification>(
&self,
secp: &secp256k1_zkp::Secp256k1<C>,
) -> Result<BtcScript, Error>
where
Pk: ToPublicKey,
{
self.bitcoin_witness_script(secp)
}
/// Get the corresponding elements descriptor that would be used
/// at redeem time by the user.
/// Users can use the DescrpitorTrait operations on the output Descriptor
/// to obtain the characteristics of the elements descriptor.
pub fn into_user_descriptor(self) -> Descriptor<Pk, CovenantExt<CovExtArgs>> {
self.elem_desc
}
}