|
| 1 | +// Miniscript |
| 2 | +// Written in 2020 by rust-miniscript developers |
| 3 | +// |
| 4 | +// To the extent possible under law, the author(s) have dedicated all |
| 5 | +// copyright and related and neighboring rights to this software to |
| 6 | +// the public domain worldwide. This software is distributed without |
| 7 | +// any warranty. |
| 8 | +// |
| 9 | +// You should have received a copy of the CC0 Public Domain Dedication |
| 10 | +// along with this software. |
| 11 | +// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. |
| 12 | +// |
| 13 | + |
| 14 | +//! # Bare Output Descriptors |
| 15 | +//! |
| 16 | +//! Implementation of Bare Descriptors (i.e descriptors that are) |
| 17 | +//! wrapped inside wsh, or sh fragments. |
| 18 | +//! Also includes pk, and pkh descriptors |
| 19 | +//! |
| 20 | +
|
| 21 | +use std::{fmt, str::FromStr}; |
| 22 | + |
| 23 | +use bitcoin::{self, blockdata::script, Script}; |
| 24 | + |
| 25 | +use expression::{self, FromTree}; |
| 26 | +use miniscript::context::ScriptContext; |
| 27 | +use policy::{semantic, Liftable}; |
| 28 | +use util::{varint_len, witness_to_scriptsig}; |
| 29 | +use {BareCtx, Error, Miniscript, MiniscriptKey, Satisfier, ToPublicKey}; |
| 30 | + |
| 31 | +use super::{ |
| 32 | + checksum::{desc_checksum, verify_checksum}, |
| 33 | + DescriptorTrait, |
| 34 | +}; |
| 35 | + |
| 36 | +/// Create a Bare Descriptor. That is descriptor that is |
| 37 | +/// not wrapped in sh or wsh. This covers the Pk descriptor |
| 38 | +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] |
| 39 | +pub struct Bare<Pk: MiniscriptKey> { |
| 40 | + /// underlying miniscript |
| 41 | + ms: Miniscript<Pk, BareCtx>, |
| 42 | +} |
| 43 | + |
| 44 | +impl<Pk: MiniscriptKey> Bare<Pk> { |
| 45 | + /// Create a new raw descriptor |
| 46 | + pub fn new(ms: Miniscript<Pk, BareCtx>) -> Result<Self, Error> { |
| 47 | + // do the top-level checks |
| 48 | + BareCtx::top_level_checks(&ms)?; |
| 49 | + Ok(Self { ms: ms }) |
| 50 | + } |
| 51 | + |
| 52 | + /// get the inner |
| 53 | + pub fn as_inner(&self) -> &Miniscript<Pk, BareCtx> { |
| 54 | + &self.ms |
| 55 | + } |
| 56 | +} |
| 57 | + |
| 58 | +impl<Pk: MiniscriptKey> fmt::Debug for Bare<Pk> { |
| 59 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 60 | + write!(f, "{:?}", self.ms) |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +impl<Pk: MiniscriptKey> fmt::Display for Bare<Pk> { |
| 65 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 66 | + let desc = format!("{}", self.ms); |
| 67 | + let checksum = desc_checksum(&desc).map_err(|_| fmt::Error)?; |
| 68 | + write!(f, "{}#{}", &desc, &checksum) |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +impl<Pk: MiniscriptKey> Liftable<Pk> for Bare<Pk> { |
| 73 | + fn lift(&self) -> Result<semantic::Policy<Pk>, Error> { |
| 74 | + self.ms.lift() |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +impl<Pk: MiniscriptKey> FromTree for Bare<Pk> |
| 79 | +where |
| 80 | + <Pk as FromStr>::Err: ToString, |
| 81 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 82 | +{ |
| 83 | + fn from_tree(top: &expression::Tree) -> Result<Self, Error> { |
| 84 | + let sub = Miniscript::<Pk, BareCtx>::from_tree(&top)?; |
| 85 | + BareCtx::top_level_checks(&sub)?; |
| 86 | + Bare::new(sub) |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +impl<Pk: MiniscriptKey> FromStr for Bare<Pk> |
| 91 | +where |
| 92 | + <Pk as FromStr>::Err: ToString, |
| 93 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 94 | +{ |
| 95 | + type Err = Error; |
| 96 | + |
| 97 | + fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 98 | + let desc_str = verify_checksum(s)?; |
| 99 | + let top = expression::Tree::from_str(desc_str)?; |
| 100 | + Self::from_tree(&top) |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Bare<Pk> |
| 105 | +where |
| 106 | + <Pk as FromStr>::Err: ToString, |
| 107 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 108 | +{ |
| 109 | + fn sanity_check(&self) -> Result<(), Error> { |
| 110 | + self.ms.sanity_check()?; |
| 111 | + Ok(()) |
| 112 | + } |
| 113 | + |
| 114 | + fn address<ToPkCtx: Copy>( |
| 115 | + &self, |
| 116 | + _to_pk_ctx: ToPkCtx, |
| 117 | + _network: bitcoin::Network, |
| 118 | + ) -> Option<bitcoin::Address> |
| 119 | + where |
| 120 | + Pk: ToPublicKey<ToPkCtx>, |
| 121 | + { |
| 122 | + None |
| 123 | + } |
| 124 | + |
| 125 | + fn script_pubkey<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 126 | + where |
| 127 | + Pk: ToPublicKey<ToPkCtx>, |
| 128 | + { |
| 129 | + self.ms.encode(to_pk_ctx) |
| 130 | + } |
| 131 | + |
| 132 | + fn unsigned_script_sig<ToPkCtx: Copy>(&self, _to_pk_ctx: ToPkCtx) -> Script |
| 133 | + where |
| 134 | + Pk: ToPublicKey<ToPkCtx>, |
| 135 | + { |
| 136 | + Script::new() |
| 137 | + } |
| 138 | + |
| 139 | + fn witness_script<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 140 | + where |
| 141 | + Pk: ToPublicKey<ToPkCtx>, |
| 142 | + { |
| 143 | + self.ms.encode(to_pk_ctx) |
| 144 | + } |
| 145 | + |
| 146 | + fn get_satisfaction<ToPkCtx, S>( |
| 147 | + &self, |
| 148 | + satisfier: S, |
| 149 | + to_pk_ctx: ToPkCtx, |
| 150 | + ) -> Result<(Vec<Vec<u8>>, Script), Error> |
| 151 | + where |
| 152 | + ToPkCtx: Copy, |
| 153 | + Pk: ToPublicKey<ToPkCtx>, |
| 154 | + S: Satisfier<ToPkCtx, Pk>, |
| 155 | + { |
| 156 | + let ms = self.ms.satisfy(satisfier, to_pk_ctx)?; |
| 157 | + let script_sig = witness_to_scriptsig(&ms); |
| 158 | + let witness = vec![]; |
| 159 | + Ok((witness, script_sig)) |
| 160 | + } |
| 161 | + |
| 162 | + fn max_satisfaction_weight<ToPkCtx: Copy>(&self) -> Option<usize> |
| 163 | + where |
| 164 | + Pk: ToPublicKey<ToPkCtx>, |
| 165 | + { |
| 166 | + let scriptsig_len = self.ms.max_satisfaction_size()?; |
| 167 | + Some(4 * (varint_len(scriptsig_len) + scriptsig_len)) |
| 168 | + } |
| 169 | + |
| 170 | + fn script_code<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 171 | + where |
| 172 | + Pk: ToPublicKey<ToPkCtx>, |
| 173 | + { |
| 174 | + self.script_pubkey(to_pk_ctx) |
| 175 | + } |
| 176 | +} |
| 177 | + |
| 178 | +/// A bare PkH descriptor at top level |
| 179 | +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] |
| 180 | +pub struct Pkh<Pk: MiniscriptKey> { |
| 181 | + /// underlying publickey |
| 182 | + pk: Pk, |
| 183 | +} |
| 184 | + |
| 185 | +impl<Pk: MiniscriptKey> Pkh<Pk> { |
| 186 | + /// Create a new Pkh descriptor |
| 187 | + pub fn new(pk: Pk) -> Self { |
| 188 | + // do the top-level checks |
| 189 | + Self { pk: pk } |
| 190 | + } |
| 191 | + |
| 192 | + /// Get the inner key |
| 193 | + pub fn as_inner(&self) -> &Pk { |
| 194 | + &self.pk |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +impl<Pk: MiniscriptKey> fmt::Debug for Pkh<Pk> { |
| 199 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 200 | + write!(f, "pkh({:?})", self.pk) |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +impl<Pk: MiniscriptKey> fmt::Display for Pkh<Pk> { |
| 205 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 206 | + let desc = format!("pkh({})", self.pk); |
| 207 | + let checksum = desc_checksum(&desc).map_err(|_| fmt::Error)?; |
| 208 | + write!(f, "{}#{}", &desc, &checksum) |
| 209 | + } |
| 210 | +} |
| 211 | + |
| 212 | +impl<Pk: MiniscriptKey> Liftable<Pk> for Pkh<Pk> { |
| 213 | + fn lift(&self) -> Result<semantic::Policy<Pk>, Error> { |
| 214 | + Ok(semantic::Policy::KeyHash(self.pk.to_pubkeyhash())) |
| 215 | + } |
| 216 | +} |
| 217 | + |
| 218 | +impl<Pk: MiniscriptKey> FromTree for Pkh<Pk> |
| 219 | +where |
| 220 | + <Pk as FromStr>::Err: ToString, |
| 221 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 222 | +{ |
| 223 | + fn from_tree(top: &expression::Tree) -> Result<Self, Error> { |
| 224 | + if top.name == "pkh" && top.args.len() == 1 { |
| 225 | + Ok(Pkh::new(expression::terminal(&top.args[0], |pk| { |
| 226 | + Pk::from_str(pk) |
| 227 | + })?)) |
| 228 | + } else { |
| 229 | + Err(Error::Unexpected(format!( |
| 230 | + "{}({} args) while parsing pkh descriptor", |
| 231 | + top.name, |
| 232 | + top.args.len(), |
| 233 | + ))) |
| 234 | + } |
| 235 | + } |
| 236 | +} |
| 237 | + |
| 238 | +impl<Pk: MiniscriptKey> FromStr for Pkh<Pk> |
| 239 | +where |
| 240 | + <Pk as FromStr>::Err: ToString, |
| 241 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 242 | +{ |
| 243 | + type Err = Error; |
| 244 | + |
| 245 | + fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 246 | + let desc_str = verify_checksum(s)?; |
| 247 | + let top = expression::Tree::from_str(desc_str)?; |
| 248 | + Self::from_tree(&top) |
| 249 | + } |
| 250 | +} |
| 251 | + |
| 252 | +impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for Pkh<Pk> |
| 253 | +where |
| 254 | + <Pk as FromStr>::Err: ToString, |
| 255 | + <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString, |
| 256 | +{ |
| 257 | + fn sanity_check(&self) -> Result<(), Error> { |
| 258 | + Ok(()) |
| 259 | + } |
| 260 | + |
| 261 | + fn address<ToPkCtx: Copy>( |
| 262 | + &self, |
| 263 | + to_pk_ctx: ToPkCtx, |
| 264 | + network: bitcoin::Network, |
| 265 | + ) -> Option<bitcoin::Address> |
| 266 | + where |
| 267 | + Pk: ToPublicKey<ToPkCtx>, |
| 268 | + { |
| 269 | + Some(bitcoin::Address::p2pkh( |
| 270 | + &self.pk.to_public_key(to_pk_ctx), |
| 271 | + network, |
| 272 | + )) |
| 273 | + } |
| 274 | + |
| 275 | + fn script_pubkey<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 276 | + where |
| 277 | + Pk: ToPublicKey<ToPkCtx>, |
| 278 | + { |
| 279 | + let addr = |
| 280 | + bitcoin::Address::p2pkh(&self.pk.to_public_key(to_pk_ctx), bitcoin::Network::Bitcoin); |
| 281 | + addr.script_pubkey() |
| 282 | + } |
| 283 | + |
| 284 | + fn unsigned_script_sig<ToPkCtx: Copy>(&self, _to_pk_ctx: ToPkCtx) -> Script |
| 285 | + where |
| 286 | + Pk: ToPublicKey<ToPkCtx>, |
| 287 | + { |
| 288 | + Script::new() |
| 289 | + } |
| 290 | + |
| 291 | + fn witness_script<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 292 | + where |
| 293 | + Pk: ToPublicKey<ToPkCtx>, |
| 294 | + { |
| 295 | + self.script_pubkey(to_pk_ctx) |
| 296 | + } |
| 297 | + |
| 298 | + fn get_satisfaction<ToPkCtx, S>( |
| 299 | + &self, |
| 300 | + satisfier: S, |
| 301 | + to_pk_ctx: ToPkCtx, |
| 302 | + ) -> Result<(Vec<Vec<u8>>, Script), Error> |
| 303 | + where |
| 304 | + ToPkCtx: Copy, |
| 305 | + Pk: ToPublicKey<ToPkCtx>, |
| 306 | + S: Satisfier<ToPkCtx, Pk>, |
| 307 | + { |
| 308 | + if let Some(sig) = satisfier.lookup_sig(&self.pk, to_pk_ctx) { |
| 309 | + let mut sig_vec = sig.0.serialize_der().to_vec(); |
| 310 | + sig_vec.push(sig.1.as_u32() as u8); |
| 311 | + let script_sig = script::Builder::new() |
| 312 | + .push_slice(&sig_vec[..]) |
| 313 | + .push_key(&self.pk.to_public_key(to_pk_ctx)) |
| 314 | + .into_script(); |
| 315 | + let witness = vec![]; |
| 316 | + Ok((witness, script_sig)) |
| 317 | + } else { |
| 318 | + Err(Error::MissingSig(self.pk.to_public_key(to_pk_ctx))) |
| 319 | + } |
| 320 | + } |
| 321 | + |
| 322 | + fn max_satisfaction_weight<ToPkCtx: Copy>(&self) -> Option<usize> |
| 323 | + where |
| 324 | + Pk: ToPublicKey<ToPkCtx>, |
| 325 | + { |
| 326 | + Some(4 * (1 + 73 + self.pk.serialized_len())) |
| 327 | + } |
| 328 | + |
| 329 | + fn script_code<ToPkCtx: Copy>(&self, to_pk_ctx: ToPkCtx) -> Script |
| 330 | + where |
| 331 | + Pk: ToPublicKey<ToPkCtx>, |
| 332 | + { |
| 333 | + self.script_pubkey(to_pk_ctx) |
| 334 | + } |
| 335 | +} |
0 commit comments