Skip to content

Commit ffc3ea0

Browse files
committed
Merge #96: Pegin desc wildcard
624e3f4 create an address matching the fed desc (Riccardo Casatta) 59362c8 remove unused lint cfg causing warning (Riccardo Casatta) 2f1e07b Add Pegin::derived_descriptor (Riccardo Casatta) f77617b Refactor out the fed peg desc in a function (Riccardo Casatta) 1a22725 Remove generic in Pegin descriptor for `fed_desc` (Riccardo Casatta) Pull request description: On top of #95 draft PR to investigate the derivability of a bunch of addresses from a pegin descriptor. Use the following assumption * federation descriptor is using only `bitcoin::PublicKey` ACKs for top commit: apoelstra: ACK 624e3f4; successfully ran local tests Tree-SHA512: 8861ff169aac8867c96c0950a2898b89f2a2aa35f3dff8ec11bc78f3d0cc2b6f0207a489637338f8df65b9c4ac5e947c1077a918d3aea3ffe1e70aebadcdbf7e
2 parents d3037cc + 624e3f4 commit ffc3ea0

File tree

3 files changed

+97
-29
lines changed

3 files changed

+97
-29
lines changed

Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ bitcoin = { version = "0.32.0", features = ["base64"] }
3535
secp256k1 = { version = "0.29.0", features = ["rand-std"] }
3636
actual-base64 = { package = "base64", version = "0.13.0" }
3737

38-
[lints.rust]
39-
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(miniscript_bench)'] }
40-
4138
[[example]]
4239
name = "htlc"
4340
required-features = ["compiler"]

src/descriptor/pegin/dynafed_pegin.rs

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use std::convert::TryFrom;
2424
use std::fmt;
2525

2626
use bitcoin::blockdata::script::{self, PushBytes};
27-
use bitcoin::{self, ScriptBuf as BtcScript, Weight};
27+
use bitcoin::{self, PublicKey, ScriptBuf as BtcScript, Weight};
28+
use bitcoin_miniscript::descriptor::DescriptorType;
2829
use elements::secp256k1_zkp;
2930

3031
use crate::descriptor::checksum::{self, verify_checksum};
@@ -33,15 +34,15 @@ use crate::extensions::{CovExtArgs, CovenantExt};
3334
use crate::policy::{semantic, Liftable};
3435
use crate::{
3536
tweak_key, BtcDescriptor, BtcError, BtcFromTree, BtcLiftable, BtcPolicy, BtcSatisfier, BtcTree,
36-
Descriptor, Error, MiniscriptKey, ToPublicKey,
37+
Descriptor, DescriptorPublicKey, Error, MiniscriptKey, ToPublicKey,
3738
};
3839

3940
/// New Pegin Descriptor with Miniscript support
4041
/// Useful with dynamic federations
4142
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
4243
pub struct Pegin<Pk: MiniscriptKey> {
4344
/// The untweaked pegin bitcoin descriptor
44-
pub fed_desc: BtcDescriptor<Pk>,
45+
pub fed_desc: BtcDescriptor<PublicKey>,
4546
/// The redeem elements descriptor
4647
///
4748
/// TODO: Allow pegin redeem descriptor with extensions
@@ -51,7 +52,7 @@ pub struct Pegin<Pk: MiniscriptKey> {
5152
impl<Pk: MiniscriptKey> Pegin<Pk> {
5253
/// Create a new LegacyPegin descriptor
5354
pub fn new(
54-
fed_desc: BtcDescriptor<Pk>,
55+
fed_desc: BtcDescriptor<PublicKey>,
5556
elem_desc: Descriptor<Pk, CovenantExt<CovExtArgs>>,
5657
) -> Self {
5758
Self {
@@ -61,6 +62,18 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
6162
}
6263
}
6364

65+
impl Pegin<DescriptorPublicKey> {
66+
pub fn derived_descriptor<C: secp256k1_zkp::Verification>(
67+
&self,
68+
arg: u32,
69+
secp: &secp256k1_zkp::Secp256k1<C>,
70+
) -> Result<Pegin<PublicKey>, Error> {
71+
let elem_desc = self.elem_desc.at_derivation_index(arg)?;
72+
let elem_desc = elem_desc.derived_descriptor(&secp)?;
73+
Ok(Pegin::new(self.fed_desc.clone(), elem_desc))
74+
}
75+
}
76+
6477
impl<Pk: MiniscriptKey> fmt::Debug for Pegin<Pk> {
6578
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6679
write!(f, "pegin({:?},{:?})", self.fed_desc, self.elem_desc)
@@ -76,15 +89,15 @@ impl<Pk: MiniscriptKey> fmt::Display for Pegin<Pk> {
7689
}
7790
}
7891

79-
impl<Pk: MiniscriptKey> Liftable<Pk> for Pegin<Pk> {
80-
fn lift(&self) -> Result<semantic::Policy<Pk>, Error> {
92+
impl<Pk: MiniscriptKey> Liftable<PublicKey> for Pegin<Pk> {
93+
fn lift(&self) -> Result<semantic::Policy<PublicKey>, Error> {
8194
let btc_pol = BtcLiftable::lift(&self.fed_desc)?;
8295
Liftable::lift(&btc_pol)
8396
}
8497
}
8598

86-
impl<Pk: MiniscriptKey> BtcLiftable<Pk> for Pegin<Pk> {
87-
fn lift(&self) -> Result<BtcPolicy<Pk>, BtcError> {
99+
impl<Pk: MiniscriptKey> BtcLiftable<PublicKey> for Pegin<Pk> {
100+
fn lift(&self) -> Result<BtcPolicy<PublicKey>, BtcError> {
88101
self.fed_desc.lift()
89102
}
90103
}
@@ -101,7 +114,7 @@ impl_from_tree!(
101114
// TODO: Confirm with Andrew about the descriptor type for dynafed
102115
// Assuming sh(wsh) for now.
103116

104-
let fed_desc = BtcDescriptor::<Pk>::from_tree(&ms_expr)?;
117+
let fed_desc = BtcDescriptor::<PublicKey>::from_tree(&ms_expr)?;
105118
let elem_desc = Descriptor::<Pk, CovenantExt<CovExtArgs>>::from_tree(&top.args[1])?;
106119
Ok(Pegin::new(fed_desc, elem_desc))
107120
} else {
@@ -146,13 +159,21 @@ impl<Pk: MiniscriptKey> Pegin<Pk> {
146159
where
147160
Pk: ToPublicKey,
148161
{
149-
// TODO
150-
Ok(bitcoin::Address::p2shwsh(
151-
&self
152-
.bitcoin_witness_script(secp)
153-
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
154-
network,
155-
))
162+
match self.fed_desc.desc_type() {
163+
DescriptorType::Wsh => Ok(bitcoin::Address::p2wsh(
164+
&self
165+
.bitcoin_witness_script(secp)
166+
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
167+
network,
168+
)),
169+
DescriptorType::ShWsh => Ok(bitcoin::Address::p2shwsh(
170+
&self
171+
.bitcoin_witness_script(secp)
172+
.expect("DO this cleanly after TR. Pay to taproot pegins unspecified till now"),
173+
network,
174+
)),
175+
_ => return Err(Error::UnsupportedAddressForPegin),
176+
}
156177
}
157178

158179
/// Computes the bitcoin scriptpubkey of the descriptor.
@@ -309,11 +330,23 @@ where
309330

310331
#[cfg(test)]
311332
mod tests {
333+
use bitcoin::PublicKey;
312334
use elements::hex::FromHex;
313335

314336
use crate::descriptor::pegin::Pegin;
315337
use crate::{BtcDescriptor, ConfidentialDescriptor, DescriptorPublicKey};
316338

339+
fn fed_peg_desc() -> BtcDescriptor<PublicKey> {
340+
let s = bitcoin::ScriptBuf::from_hex("5b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc401021031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb2103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5fae736402c00fb269522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb53ae68").unwrap();
341+
342+
type Segwitv0Script =
343+
bitcoin_miniscript::Miniscript<bitcoin::PublicKey, bitcoin_miniscript::Segwitv0>;
344+
345+
let m = Segwitv0Script::parse(&s).unwrap();
346+
assert_eq!(m.encode(), s);
347+
BtcDescriptor::<_>::new_wsh(m).unwrap()
348+
}
349+
317350
// test vector created with:
318351
// ```
319352
// $ elements-cli getnetworkinfo | jq .version
@@ -330,16 +363,7 @@ mod tests {
330363
// ```
331364
#[test]
332365
fn test_pegin() {
333-
let fedpegscript ="5b21020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b678172612102675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af992102896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d4821029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c2102a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc401021031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb2103079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b2103111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2210318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa08401742103230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de121035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a62103bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c2103cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d175462103d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d4248282103ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a5fae736402c00fb269522103aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79210291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807210386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb53ae68";
334-
let s = bitcoin::ScriptBuf::from_hex(fedpegscript).unwrap();
335-
336-
type Segwitv0Script =
337-
bitcoin_miniscript::Miniscript<bitcoin::PublicKey, bitcoin_miniscript::Segwitv0>;
338-
339-
let m = Segwitv0Script::parse(&s).unwrap();
340-
assert_eq!(m.encode(), s);
341-
342-
let d = BtcDescriptor::<_>::new_wsh(m).unwrap();
366+
let d = fed_peg_desc();
343367

344368
let fedpegdesc = "wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb))))#7jwwklk4";
345369
assert_eq!(&d.to_string(), fedpegdesc);
@@ -362,4 +386,34 @@ mod tests {
362386

363387
assert_eq!(pegin.to_string(), "pegin(wsh(or_d(multi(11,020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261,02675333a4e4b8fb51d9d4e22fa5a8eaced3fdac8a8cbf9be8c030f75712e6af99,02896807d54bc55c24981f24a453c60ad3e8993d693732288068a23df3d9f50d48,029e51a5ef5db3137051de8323b001749932f2ff0d34c82e96a2c2461de96ae56c,02a4e1a9638d46923272c266631d94d36bdb03a64ee0e14c7518e49d2f29bc4010,031c41fdbcebe17bec8d49816e00ca1b5ac34766b91c9f2ac37d39c63e5e008afb,03079e252e85abffd3c401a69b087e590a9b86f33f574f08129ccbd3521ecf516b,03111cf405b627e22135b3b3733a4a34aa5723fb0f58379a16d32861bf576b0ec2,0318f331b3e5d38156da6633b31929c5b220349859cc9ca3d33fb4e68aa0840174,03230dae6b4ac93480aeab26d000841298e3b8f6157028e47b0897c1e025165de1,035abff4281ff00660f99ab27bb53e6b33689c2cd8dcd364bc3c90ca5aea0d71a6,03bd45cddfacf2083b14310ae4a84e25de61e451637346325222747b157446614c,03cc297026b06c71cbfa52089149157b5ff23de027ac5ab781800a578192d17546,03d3bde5d63bdb3a6379b461be64dad45eabff42f758543a9645afd42f6d424828,03ed1e8d5109c9ed66f7941bc53cc71137baa76d50d274bda8d5e8ffbd6e61fe9a),and_v(v:older(4032),multi(2,03aab896d53a8e7d6433137bbba940f9c521e085dd07e60994579b64a6d992cf79,0291b7d0b1b692f8f524516ed950872e5da10fb1b808b5a526dedc6fed1cf29807,0386aa9372fbab374593466bc5451dc59954e90787f08060964d95c87ef34ca5bb)))),elwpkh(0321da398ca2ddc09be89caa26e6730ae84751b6ea3a1ca46aa365bb5e1c3d9620))#qp4fan9q");
364388
}
389+
390+
#[test]
391+
fn test_pegin_derive() {
392+
let elem_desc = "ct(slip77(ab5824f4477b4ebb00a132adfd8eb0b7935cf24f6ac151add5d1913db374ce92),elwpkh([759db348/84'/1'/0']tpubDCRMaF33e44pcJj534LXVhFbHibPbJ5vuLhSSPFAw57kYURv4tzXFL6LSnd78bkjqdmE3USedkbpXJUPA1tdzKfuYSL7PianceqAhwL2UkA/0/*))";
393+
let elem_desc: ConfidentialDescriptor<DescriptorPublicKey> = elem_desc.parse().unwrap();
394+
let fed_peg_desc = fed_peg_desc();
395+
let pegin = Pegin::new(fed_peg_desc, elem_desc.descriptor);
396+
let secp = secp256k1::Secp256k1::new();
397+
398+
let address_0 = pegin
399+
.derived_descriptor(0, &secp)
400+
.unwrap()
401+
.bitcoin_address(bitcoin::Network::Bitcoin, &secp)
402+
.unwrap();
403+
assert_eq!(
404+
address_0.to_string(),
405+
"bc1qqkq6czql4zqwsylgrfzttjrn5wjeqmwfq5yn80p39amxtnkng9lsn6c5qr"
406+
);
407+
408+
let address_1 = pegin
409+
.derived_descriptor(1, &secp)
410+
.unwrap()
411+
.bitcoin_address(bitcoin::Network::Bitcoin, &secp)
412+
.unwrap();
413+
assert_ne!(address_0, address_1);
414+
assert_eq!(
415+
address_1.to_string(),
416+
"bc1qmevs3n40t394230lptclz55rmxkmr7dmnqhuflxf0cezdupsmvdsk25n3m"
417+
);
418+
}
365419
}

src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,12 @@ pub enum Error {
373373
/// At least two BIP389 key expressions in the descriptor contain tuples of
374374
/// derivation indexes of different lengths.
375375
MultipathDescLenMismatch,
376+
377+
/// The federation descriptor has a type not supported
378+
UnsupportedAddressForPegin,
379+
380+
/// Conversion error in descriptor
381+
Conversion(descriptor::ConversionError),
376382
}
377383

378384
#[doc(hidden)]
@@ -449,6 +455,12 @@ impl From<bitcoin::address::ParseError> for Error {
449455
}
450456
}
451457

458+
impl From<descriptor::ConversionError> for Error {
459+
fn from(e: descriptor::ConversionError) -> Error {
460+
Error::Conversion(e)
461+
}
462+
}
463+
452464
fn errstr(s: &str) -> Error {
453465
Error::Unexpected(s.to_owned())
454466
}
@@ -530,6 +542,9 @@ impl fmt::Display for Error {
530542
Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"),
531543
Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"),
532544
Error::MultipathDescLenMismatch => write!(f, "At least two BIP389 key expressions in the descriptor contain tuples of derivation indexes of different lengths"),
545+
Error::Conversion(ref e) => e.fmt(f),
546+
Error::UnsupportedAddressForPegin => write!(f, "Cannot create the address from the pegin descriptor, the federation descriptor is of an unsuppported type"),
547+
533548
}
534549
}
535550
}
@@ -568,6 +583,7 @@ impl error::Error for Error {
568583
| BareDescriptorAddr
569584
| TaprootSpendInfoUnavialable
570585
| TrNoScriptCode
586+
| UnsupportedAddressForPegin
571587
| TrNoExplicitScript => None,
572588
MultipathDescLenMismatch => None,
573589
BtcError(e) => Some(e),
@@ -584,6 +600,7 @@ impl error::Error for Error {
584600
ContextError(e) => Some(e),
585601
AnalysisError(e) => Some(e),
586602
PubKeyCtxError(e, _) => Some(e),
603+
Conversion(e) => Some(e),
587604
}
588605
}
589606
}

0 commit comments

Comments
 (0)