Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion fuzz/fuzz_targets/compile_descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use miniscript::Segwitv0;
use miniscript::{policy, DummyKey, Miniscript};
use policy::Liftable;

use miniscript::NoExt;
use std::str::FromStr;

type DummyScript = Miniscript<DummyKey, Segwitv0>;
type DummyScript = Miniscript<DummyKey, Segwitv0, NoExt>;
type DummyPolicy = policy::Concrete<DummyKey>;

fn do_test(data: &[u8]) {
Expand Down
3 changes: 2 additions & 1 deletion fuzz/fuzz_targets/roundtrip_miniscript_script.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
extern crate elements_miniscript as miniscript;

use miniscript::elements::script;
use miniscript::AllExt;
use miniscript::Miniscript;
use miniscript::Segwitv0;

fn do_test(data: &[u8]) {
// Try round-tripping as a script
let script = script::Script::from(data.to_owned());

if let Ok(pt) = Miniscript::<_, Segwitv0>::parse(&script) {
if let Ok(pt) = Miniscript::<_, Segwitv0, AllExt>::parse(&script) {
let output = pt.encode();
assert_eq!(pt.script_size(), output.len());
assert_eq!(output, script);
Expand Down
3 changes: 2 additions & 1 deletion fuzz/fuzz_targets/roundtrip_miniscript_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ extern crate regex;
use regex::Regex;
use std::str::FromStr;

use miniscript::AllExt;
use miniscript::DummyKey;
use miniscript::Miniscript;
use miniscript::Segwitv0;

fn do_test(data: &[u8]) {
let s = String::from_utf8_lossy(data);
if let Ok(desc) = Miniscript::<DummyKey, Segwitv0>::from_str(&s) {
if let Ok(desc) = Miniscript::<DummyKey, Segwitv0, AllExt>::from_str(&s) {
let output = desc.to_string();

let multi_wrap_pk_re = Regex::new("([a-z]+)c:pk_k\\(").unwrap();
Expand Down
12 changes: 7 additions & 5 deletions src/descriptor/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ use {
TranslatePk,
};

use NoExt;

use super::{
checksum::{desc_checksum, verify_checksum},
DescriptorTrait, ElementsTrait, ELMTS_STR,
Expand All @@ -42,24 +44,24 @@ use super::{
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Bare<Pk: MiniscriptKey> {
/// underlying miniscript
ms: Miniscript<Pk, BareCtx>,
ms: Miniscript<Pk, BareCtx, NoExt>,
}

impl<Pk: MiniscriptKey> Bare<Pk> {
/// Create a new raw descriptor
pub fn new(ms: Miniscript<Pk, BareCtx>) -> Result<Self, Error> {
pub fn new(ms: Miniscript<Pk, BareCtx, NoExt>) -> Result<Self, Error> {
// do the top-level checks
BareCtx::top_level_checks(&ms)?;
Ok(Self { ms: ms })
}

/// get the inner
pub fn into_inner(self) -> Miniscript<Pk, BareCtx> {
pub fn into_inner(self) -> Miniscript<Pk, BareCtx, NoExt> {
self.ms
}

/// get the inner
pub fn as_inner(&self) -> &Miniscript<Pk, BareCtx> {
pub fn as_inner(&self) -> &Miniscript<Pk, BareCtx, NoExt> {
&self.ms
}
}
Expand Down Expand Up @@ -98,7 +100,7 @@ where
name: top.name.split_at(2).1,
args: top.args.clone(),
};
let sub = Miniscript::<Pk, BareCtx>::from_tree(&new_tree)?;
let sub = Miniscript::<Pk, BareCtx, NoExt>::from_tree(&new_tree)?;
BareCtx::top_level_checks(&sub)?;
Bare::new(sub)
} else {
Expand Down
70 changes: 49 additions & 21 deletions src/descriptor/covenants/cov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ use {
ForEach, ForEachKey, Miniscript, ScriptContext, Segwitv0, TranslatePk,
};

use Extension;

use super::super::{
checksum::{desc_checksum, verify_checksum},
ElementsTrait, ELMTS_STR,
Expand All @@ -85,33 +87,34 @@ pub(crate) const COV_SCRIPT_SIZE: usize = 120;
pub(crate) const COV_SCRIPT_OPCODE_COST: usize = 74;
/// The covenant descriptor
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CovenantDescriptor<Pk: MiniscriptKey> {
pub struct CovenantDescriptor<Pk: MiniscriptKey, Ext: Extension<Pk>> {
/// the pk constraining the Covenant
/// The key over which we want CHECKSIGFROMSTACK
pub(crate) pk: Pk,
/// the underlying Miniscript
/// Must be under segwit context
pub(crate) ms: Miniscript<Pk, Segwitv0>,
// All known extensions are enabled in covenant descriptor
pub(crate) ms: Miniscript<Pk, Segwitv0, Ext>,
}

impl<Pk: MiniscriptKey> CovenantDescriptor<Pk> {
impl<Pk: MiniscriptKey, Ext: Extension<Pk>> CovenantDescriptor<Pk, Ext> {
/// Get the pk from covenant
pub fn pk(&self) -> &Pk {
&self.pk
}

/// Get a reference to Miniscript inside covenant
pub fn to_ms(&self) -> &Miniscript<Pk, Segwitv0> {
pub fn to_ms(&self) -> &Miniscript<Pk, Segwitv0, Ext> {
&self.ms
}

/// Consume self and return inner miniscript
pub fn into_ms(self) -> Miniscript<Pk, Segwitv0> {
pub fn into_ms(self) -> Miniscript<Pk, Segwitv0, Ext> {
self.ms
}

/// Create a new Self from components
pub fn new(pk: Pk, ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
pub fn new(pk: Pk, ms: Miniscript<Pk, Segwitv0, Ext>) -> Result<Self, Error> {
// // 1) Check the 201 opcode count here
let ms_op_count = ms.ext.ops_count_sat;
// statically computed
Expand Down Expand Up @@ -205,7 +208,7 @@ impl<Pk: MiniscriptKey> CovenantDescriptor<Pk> {
}
}

impl CovenantDescriptor<bitcoin::PublicKey> {
impl<Ext: Extension<bitcoin::PublicKey>> CovenantDescriptor<bitcoin::PublicKey, Ext> {
/// Check if the given script is a covenant descriptor
/// Consumes the iterator so that only remaining miniscript
/// needs to be parsed from the iterator
Expand Down Expand Up @@ -244,21 +247,25 @@ impl CovenantDescriptor<bitcoin::PublicKey> {
// All code for covenants can thus be separated in a module
// This parsing is parse_insane
pub fn parse_insane(script: &script::Script) -> Result<Self, Error> {
let (pk, ms) = Self::parse_cov_components(script)?;
let (pk, ms) = Self::parse_cov_components::<_>(script)?;
Self::new(pk, ms)
}

// Utility function to parse the components of cov
// descriptor. This allows us to parse Miniscript with
// it's context so that it can be used with NoChecks
// context while using the interpreter
pub(crate) fn parse_cov_components<Ctx: ScriptContext>(
pub(crate) fn parse_cov_components<Ctx>(
script: &script::Script,
) -> Result<(bitcoin::PublicKey, Miniscript<bitcoin::PublicKey, Ctx>), Error> {
) -> Result<(bitcoin::PublicKey, Miniscript<bitcoin::PublicKey, Ctx, Ext>), Error>
where
Ctx: ScriptContext,
Ext: Extension<bitcoin::PublicKey>,
{
let tokens = lex(script)?;
let mut iter = TokenIter::new(tokens);

let pk = CovenantDescriptor::<bitcoin::PublicKey>::check_cov_script(&mut iter)?;
let pk = CovenantDescriptor::<bitcoin::PublicKey, Ext>::check_cov_script(&mut iter)?;
let ms = decode::parse(&mut iter)?;
Segwitv0::check_global_validity(&ms)?;
if ms.ty.corr.base != types::Base::B {
Expand All @@ -281,10 +288,11 @@ impl CovenantDescriptor<bitcoin::PublicKey> {
}
}

impl<Pk: MiniscriptKey> FromTree for CovenantDescriptor<Pk>
impl<Pk: MiniscriptKey, Ext> FromTree for CovenantDescriptor<Pk, Ext>
where
Pk: FromStr,
Pk::Hash: FromStr,
Ext: Extension<Pk>,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
{
Expand All @@ -304,42 +312,54 @@ where
}
}
}
impl<Pk: MiniscriptKey> fmt::Debug for CovenantDescriptor<Pk> {
impl<Pk, Ext> fmt::Debug for CovenantDescriptor<Pk, Ext>
where
Pk: MiniscriptKey,
Ext: Extension<Pk>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}covwsh({},{})", ELMTS_STR, self.pk, self.ms)
}
}

impl<Pk: MiniscriptKey> fmt::Display for CovenantDescriptor<Pk> {
impl<Pk, Ext> fmt::Display for CovenantDescriptor<Pk, Ext>
where
Pk: MiniscriptKey,
Ext: Extension<Pk>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let desc = format!("{}covwsh({},{})", ELMTS_STR, self.pk, self.ms);
let checksum = desc_checksum(&desc).map_err(|_| fmt::Error)?;
write!(f, "{}#{}", &desc, &checksum)
}
}

impl<Pk: MiniscriptKey> FromStr for CovenantDescriptor<Pk>
impl<Pk, Ext> FromStr for CovenantDescriptor<Pk, Ext>
where
Pk: FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
Pk: MiniscriptKey,
Ext: Extension<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)?;
CovenantDescriptor::<Pk>::from_tree(&top)
CovenantDescriptor::<Pk, Ext>::from_tree(&top)
}
}

impl<Pk: MiniscriptKey> ElementsTrait<Pk> for CovenantDescriptor<Pk>
impl<Pk, Ext> ElementsTrait<Pk> for CovenantDescriptor<Pk, Ext>
where
Pk: FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
Pk: MiniscriptKey,
Ext: Extension<Pk>,
{
fn blind_addr(
&self,
Expand All @@ -357,12 +377,14 @@ where
}
}

impl<Pk: MiniscriptKey> DescriptorTrait<Pk> for CovenantDescriptor<Pk>
impl<Pk, Ext> DescriptorTrait<Pk> for CovenantDescriptor<Pk, Ext>
where
Pk: FromStr,
Pk::Hash: FromStr,
<Pk as FromStr>::Err: ToString,
<<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString,
Pk: MiniscriptKey,
Ext: Extension<Pk>,
{
fn sanity_check(&self) -> Result<(), Error> {
self.ms.sanity_check()?;
Expand Down Expand Up @@ -443,7 +465,7 @@ where
}
}

impl<Pk: MiniscriptKey> ForEachKey<Pk> for CovenantDescriptor<Pk> {
impl<Pk: MiniscriptKey, Ext: Extension<Pk>> ForEachKey<Pk> for CovenantDescriptor<Pk, Ext> {
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
where
Pk: 'a,
Expand All @@ -453,8 +475,14 @@ impl<Pk: MiniscriptKey> ForEachKey<Pk> for CovenantDescriptor<Pk> {
}
}

impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for CovenantDescriptor<P> {
type Output = CovenantDescriptor<Q>;
impl<P, Q, Ext> TranslatePk<P, Q> for CovenantDescriptor<P, Ext>
where
P: MiniscriptKey,
Q: MiniscriptKey,
Ext: Extension<P> + TranslatePk<P, Q>,
<Ext as TranslatePk<P, Q>>::Output: Extension<Q>,
{
type Output = CovenantDescriptor<Q, <Ext as TranslatePk<P, Q>>::Output>;

fn translate_pk<Fpk, Fpkh, E>(
&self,
Expand Down
5 changes: 4 additions & 1 deletion src/descriptor/covenants/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ pub use self::script_internals::CovOperations;
#[allow(unused_imports)]
mod tests {

use AllExt;

use super::cov::*;
use super::*;
use bitcoin;
Expand Down Expand Up @@ -101,7 +103,8 @@ mod tests {
assert_eq!(desc.desc_type(), DescriptorType::Cov);
let script = desc.explicit_script();

let cov_desc = CovenantDescriptor::<bitcoin::PublicKey>::parse_insane(&script).unwrap();
let cov_desc =
CovenantDescriptor::<bitcoin::PublicKey, AllExt>::parse_insane(&script).unwrap();

assert_eq!(cov_desc.to_string(), desc.to_string());
}
Expand Down
23 changes: 14 additions & 9 deletions src/descriptor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ use elements;
use elements::secp256k1_zkp;
use elements::Script;

use AllExt;
use NoExt;

use self::checksum::verify_checksum;
use expression;
use miniscript;
Expand Down Expand Up @@ -344,8 +347,9 @@ pub enum Descriptor<Pk: MiniscriptKey> {
Sh(Sh<Pk>),
/// Pay-to-Witness-ScriptHash with Segwitv0 context
Wsh(Wsh<Pk>),
/// Covenant descriptor
Cov(CovenantDescriptor<Pk>),
/// Covenant descriptor with all known extensions
/// Downstream implementations of extensions should implement directly use descriptor API
Cov(CovenantDescriptor<Pk, AllExt>),
}

impl<Pk: MiniscriptKey> Descriptor<Pk> {
Expand All @@ -354,7 +358,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
/// Create a new pk descriptor
pub fn new_pk(pk: Pk) -> Self {
// roundabout way to constuct `c:pk_k(pk)`
let ms: Miniscript<Pk, BareCtx> =
let ms: Miniscript<Pk, BareCtx, NoExt> =
Miniscript::from_ast(miniscript::decode::Terminal::Check(Arc::new(
Miniscript::from_ast(miniscript::decode::Terminal::PkK(pk))
.expect("Type check cannot fail"),
Expand Down Expand Up @@ -385,28 +389,28 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
/// Create a new sh for a given redeem script
/// Errors when miniscript exceeds resource limits under p2sh context
/// or does not type check at the top level
pub fn new_sh(ms: Miniscript<Pk, Legacy>) -> Result<Self, Error> {
pub fn new_sh(ms: Miniscript<Pk, Legacy, NoExt>) -> Result<Self, Error> {
Ok(Descriptor::Sh(Sh::new(ms)?))
}

/// Create a new wsh descriptor from witness script
/// Errors when miniscript exceeds resource limits under p2sh context
/// or does not type check at the top level
pub fn new_wsh(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
pub fn new_wsh(ms: Miniscript<Pk, Segwitv0, NoExt>) -> Result<Self, Error> {
Ok(Descriptor::Wsh(Wsh::new(ms)?))
}

/// Create a new sh wrapped wsh descriptor with witness script
/// Errors when miniscript exceeds resource limits under wsh context
/// or does not type check at the top level
pub fn new_sh_wsh(ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
pub fn new_sh_wsh(ms: Miniscript<Pk, Segwitv0, NoExt>) -> Result<Self, Error> {
Ok(Descriptor::Sh(Sh::new_wsh(ms)?))
}

/// Create a new bare descriptor from witness script
/// Errors when miniscript exceeds resource limits under bare context
/// or does not type check at the top level
pub fn new_bare(ms: Miniscript<Pk, BareCtx>) -> Result<Self, Error> {
pub fn new_bare(ms: Miniscript<Pk, BareCtx, NoExt>) -> Result<Self, Error> {
Ok(Descriptor::Bare(Bare::new(ms)?))
}

Expand All @@ -433,7 +437,8 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
}

/// Create a new covenant descriptor
pub fn new_cov_wsh(pk: Pk, ms: Miniscript<Pk, Segwitv0>) -> Result<Self, Error> {
// All extensions are supported in wsh descriptor
pub fn new_cov_wsh(pk: Pk, ms: Miniscript<Pk, Segwitv0, AllExt>) -> Result<Self, Error> {
let cov = CovenantDescriptor::new(pk, ms)?;
Ok(Descriptor::Cov(cov))
}
Expand Down Expand Up @@ -462,7 +467,7 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
}

/// Tries to convert descriptor as a covenant descriptor
pub fn as_cov(&self) -> Result<&CovenantDescriptor<Pk>, Error> {
pub fn as_cov(&self) -> Result<&CovenantDescriptor<Pk, AllExt>, Error> {
if let Descriptor::Cov(cov) = self {
Ok(cov)
} else {
Expand Down
Loading