Skip to content

Commit dc01037

Browse files
committed
Update TranslatePk again
This fixes of the long last standing bug in rust-miniscript that allowed creating unsound miniscript using the translate APIs
1 parent 7d4a621 commit dc01037

File tree

13 files changed

+177
-98
lines changed

13 files changed

+177
-98
lines changed

src/descriptor/bare.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::policy::{semantic, Liftable};
2020
use crate::prelude::*;
2121
use crate::util::{varint_len, witness_to_scriptsig};
2222
use crate::{
23-
BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk,
24-
Translator,
23+
BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslateErr,
24+
TranslatePk, Translator,
2525
};
2626

2727
/// Create a Bare Descriptor. That is descriptor that is
@@ -191,11 +191,11 @@ where
191191
{
192192
type Output = Bare<Q>;
193193

194-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
194+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Bare<Q>, TranslateErr<E>>
195195
where
196196
T: Translator<P, Q, E>,
197197
{
198-
Ok(Bare::new(self.ms.translate_pk(t)?).expect("Translation cannot fail inside Bare"))
198+
Ok(Bare::new(self.ms.translate_pk(t)?).map_err(TranslateErr::OuterError)?)
199199
}
200200
}
201201

@@ -377,11 +377,14 @@ where
377377
{
378378
type Output = Pkh<Q>;
379379

380-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
380+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
381381
where
382382
T: Translator<P, Q, E>,
383383
{
384384
let res = Pkh::new(t.pk(&self.pk)?);
385-
Ok(res.expect("Expect will be fixed in next commit"))
385+
match res {
386+
Ok(pk) => Ok(pk),
387+
Err(e) => Err(TranslateErr::OuterError(Error::from(e))),
388+
}
386389
}
387390
}

src/descriptor/mod.rs

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::miniscript::{Legacy, Miniscript, Segwitv0};
2727
use crate::prelude::*;
2828
use crate::{
2929
expression, hash256, miniscript, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier,
30-
ToPublicKey, TranslatePk, Translator,
30+
ToPublicKey, TranslateErr, TranslatePk, Translator,
3131
};
3232

3333
mod bare;
@@ -520,7 +520,7 @@ where
520520
type Output = Descriptor<Q>;
521521

522522
/// Converts a descriptor using abstract keys to one using specific keys.
523-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
523+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
524524
where
525525
T: Translator<P, Q, E>,
526526
{
@@ -585,7 +585,10 @@ impl Descriptor<DescriptorPublicKey> {
585585

586586
translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ConversionError);
587587
}
588-
self.translate_pk(&mut Derivator(index))
588+
self.translate_pk(&mut Derivator(index)).map_err(|e| {
589+
e.try_into_translator_err()
590+
.expect("No Context errors while translating")
591+
})
589592
}
590593

591594
#[deprecated(note = "use at_derivation_index instead")]
@@ -698,9 +701,13 @@ impl Descriptor<DescriptorPublicKey> {
698701
}
699702

700703
let descriptor = Descriptor::<String>::from_str(s)?;
701-
let descriptor = descriptor
702-
.translate_pk(&mut keymap_pk)
703-
.map_err(|e| Error::Unexpected(e.to_string()))?;
704+
let descriptor = descriptor.translate_pk(&mut keymap_pk).map_err(|e| {
705+
Error::Unexpected(
706+
e.try_into_translator_err()
707+
.expect("No Outer context errors")
708+
.to_string(),
709+
)
710+
})?;
704711

705712
Ok((descriptor, keymap_pk.0))
706713
}
@@ -827,49 +834,16 @@ impl Descriptor<DescriptorPublicKey> {
827834

828835
for (i, desc) in descriptors.iter_mut().enumerate() {
829836
let mut index_choser = IndexChoser(i);
830-
*desc = desc.translate_pk(&mut index_choser)?;
837+
*desc = desc.translate_pk(&mut index_choser).map_err(|e| {
838+
e.try_into_translator_err()
839+
.expect("No Context errors possible")
840+
})?;
831841
}
832842

833843
Ok(descriptors)
834844
}
835845
}
836846

837-
impl<Pk: MiniscriptKey> Descriptor<Pk> {
838-
/// Whether this descriptor is a multipath descriptor that contains any 2 multipath keys
839-
/// with a different number of derivation paths.
840-
/// Such a descriptor is invalid according to BIP389.
841-
pub fn multipath_length_mismatch(&self) -> bool {
842-
// (Ab)use `for_each_key` to record the number of derivation paths a multipath key has.
843-
#[derive(PartialEq)]
844-
enum MultipathLenChecker {
845-
SinglePath,
846-
MultipathLen(usize),
847-
LenMismatch,
848-
}
849-
850-
let mut checker = MultipathLenChecker::SinglePath;
851-
self.for_each_key(|key| {
852-
match key.num_der_paths() {
853-
0 | 1 => {}
854-
n => match checker {
855-
MultipathLenChecker::SinglePath => {
856-
checker = MultipathLenChecker::MultipathLen(n);
857-
}
858-
MultipathLenChecker::MultipathLen(len) => {
859-
if len != n {
860-
checker = MultipathLenChecker::LenMismatch;
861-
}
862-
}
863-
MultipathLenChecker::LenMismatch => {}
864-
},
865-
}
866-
true
867-
});
868-
869-
checker == MultipathLenChecker::LenMismatch
870-
}
871-
}
872-
873847
impl Descriptor<DefiniteDescriptorKey> {
874848
/// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or
875849
/// otherwise converting them. All [`bitcoin::XOnlyPublicKey`]s are converted to by adding a
@@ -913,8 +887,14 @@ impl Descriptor<DefiniteDescriptorKey> {
913887
translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError);
914888
}
915889

916-
let derived = self.translate_pk(&mut Derivator(secp))?;
917-
Ok(derived)
890+
let derived = self.translate_pk(&mut Derivator(secp));
891+
match derived {
892+
Ok(derived) => Ok(derived),
893+
Err(e) => match e.try_into_translator_err() {
894+
Ok(e) => Err(e),
895+
Err(_) => unreachable!("No Context errors when deriving keys"),
896+
},
897+
}
918898
}
919899
}
920900

@@ -948,10 +928,6 @@ impl_from_str!(
948928
expression::FromTree::from_tree(&top)
949929
}?;
950930

951-
if desc.multipath_length_mismatch() {
952-
return Err(Error::MultipathDescLenMismatch);
953-
}
954-
955931
Ok(desc)
956932
}
957933
);
@@ -1977,7 +1953,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
19771953
// We can parse a multipath descriptors, and make it into separate single-path descriptors.
19781954
let desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<7';8h;20>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/<0;1;987>/*)))").unwrap();
19791955
assert!(desc.is_multipath());
1980-
assert!(!desc.multipath_length_mismatch());
19811956
assert_eq!(desc.into_single_descriptors().unwrap(), vec![
19821957
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/7'/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/0/*)))").unwrap(),
19831958
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/8h/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/1/*)))").unwrap(),
@@ -1987,7 +1962,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
19871962
// Even if only one of the keys is multipath.
19881963
let desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/<0;1>/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap();
19891964
assert!(desc.is_multipath());
1990-
assert!(!desc.multipath_length_mismatch());
19911965
assert_eq!(desc.into_single_descriptors().unwrap(), vec![
19921966
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/0/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap(),
19931967
Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/1/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap(),
@@ -1996,7 +1970,6 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
19961970
// We can detect regular single-path descriptors.
19971971
let notmulti_desc = Descriptor::from_str("wsh(andor(pk(tpubDEN9WSToTyy9ZQfaYqSKfmVqmq1VVLNtYfj3Vkqh67et57eJ5sTKZQBkHqSwPUsoSskJeaYnPttHe2VrkCsKA27kUaN9SDc5zhqeLzKa1rr/0'/*),older(10000),pk(tpubD8LYfn6njiA2inCoxwM7EuN3cuLVcaHAwLYeups13dpevd3nHLRdK9NdQksWXrhLQVxcUZRpnp5CkJ1FhE61WRAsHxDNAkvGkoQkAeWDYjV/8/4567/*)))").unwrap();
19981972
assert!(!notmulti_desc.is_multipath());
1999-
assert!(!notmulti_desc.multipath_length_mismatch());
20001973
assert_eq!(
20011974
notmulti_desc.clone().into_single_descriptors().unwrap(),
20021975
vec![notmulti_desc]

src/descriptor/segwitv0.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use crate::policy::{semantic, Liftable};
1818
use crate::prelude::*;
1919
use crate::util::varint_len;
2020
use crate::{
21-
Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslatePk,
22-
Translator,
21+
Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslateErr,
22+
TranslatePk, Translator,
2323
};
2424
/// A Segwitv0 wsh descriptor
2525
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
@@ -285,7 +285,7 @@ where
285285
{
286286
type Output = Wsh<Q>;
287287

288-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
288+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
289289
where
290290
T: Translator<P, Q, E>,
291291
{
@@ -486,10 +486,14 @@ where
486486
{
487487
type Output = Wpkh<Q>;
488488

489-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
489+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
490490
where
491491
T: Translator<P, Q, E>,
492492
{
493-
Ok(Wpkh::new(t.pk(&self.pk)?).expect("Uncompressed keys in Wpkh"))
493+
let res = Wpkh::new(t.pk(&self.pk)?);
494+
match res {
495+
Ok(pk) => Ok(pk),
496+
Err(e) => Err(TranslateErr::OuterError(Error::from(e))),
497+
}
494498
}
495499
}

src/descriptor/sh.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::prelude::*;
2222
use crate::util::{varint_len, witness_to_scriptsig};
2323
use crate::{
2424
push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0,
25-
ToPublicKey, TranslatePk, Translator,
25+
ToPublicKey, TranslateErr, TranslatePk, Translator,
2626
};
2727

2828
/// A Legacy p2sh Descriptor
@@ -439,7 +439,7 @@ where
439439
{
440440
type Output = Sh<Q>;
441441

442-
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, E>
442+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
443443
where
444444
T: Translator<P, Q, E>,
445445
{

src/descriptor/sortedmulti.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
1818
use crate::prelude::*;
1919
use crate::{
2020
errstr, expression, miniscript, policy, script_num_size, Error, ForEachKey, Miniscript,
21-
MiniscriptKey, Satisfier, ToPublicKey, Translator,
21+
MiniscriptKey, Satisfier, ToPublicKey, TranslateErr, Translator,
2222
};
2323

2424
/// Contents of a "sortedmulti" descriptor
@@ -87,17 +87,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
8787
pub fn translate_pk<T, Q, FuncError>(
8888
&self,
8989
t: &mut T,
90-
) -> Result<SortedMultiVec<Q, Ctx>, FuncError>
90+
) -> Result<SortedMultiVec<Q, Ctx>, TranslateErr<FuncError>>
9191
where
9292
T: Translator<Pk, Q, FuncError>,
9393
Q: MiniscriptKey,
9494
{
9595
let pks: Result<Vec<Q>, _> = self.pks.iter().map(|pk| t.pk(pk)).collect();
96-
Ok(SortedMultiVec {
97-
k: self.k,
98-
pks: pks?,
99-
phantom: PhantomData,
100-
})
96+
let res = SortedMultiVec::new(self.k, pks?).map_err(TranslateErr::OuterError)?;
97+
Ok(res)
10198
}
10299
}
103100

src/descriptor/tr.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::prelude::*;
2121
use crate::util::{varint_len, witness_size};
2222
use crate::{
2323
errstr, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap, ToPublicKey,
24-
TranslatePk, Translator,
24+
TranslateErr, TranslatePk, Translator,
2525
};
2626

2727
/// A Taproot Tree representation.
@@ -129,9 +129,9 @@ impl<Pk: MiniscriptKey> TapTree<Pk> {
129129
}
130130

131131
// Helper function to translate keys
132-
fn translate_helper<T, Q, Error>(&self, t: &mut T) -> Result<TapTree<Q>, Error>
132+
fn translate_helper<T, Q, E>(&self, t: &mut T) -> Result<TapTree<Q>, TranslateErr<E>>
133133
where
134-
T: Translator<Pk, Q, Error>,
134+
T: Translator<Pk, Q, E>,
135135
Q: MiniscriptKey,
136136
{
137137
let frag = match self {
@@ -634,7 +634,7 @@ where
634634
{
635635
type Output = Tr<Q>;
636636

637-
fn translate_pk<T, E>(&self, translate: &mut T) -> Result<Self::Output, E>
637+
fn translate_pk<T, E>(&self, translate: &mut T) -> Result<Self::Output, TranslateErr<E>>
638638
where
639639
T: Translator<P, Q, E>,
640640
{
@@ -643,7 +643,7 @@ where
643643
None => None,
644644
};
645645
let translate_desc = Tr::new(translate.pk(&self.internal_key)?, tree)
646-
.expect("This will be removed in future");
646+
.map_err(|e| TranslateErr::OuterError(e))?;
647647
Ok(translate_desc)
648648
}
649649
}

src/lib.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,57 @@ where
363363
fn hash160(&mut self, hash160: &P::Hash160) -> Result<Q::Hash160, E>;
364364
}
365365

366+
/// An enum for representing translation errors
367+
pub enum TranslateErr<E> {
368+
/// Error inside in the underlying key translation
369+
TranslatorErr(E),
370+
/// Error in the final translated structure. In some cases, the translated
371+
/// structure might not be valid under the given context. For example, translating
372+
/// from string keys to x-only keys in wsh descriptors.
373+
OuterError(Error),
374+
}
375+
376+
impl<E> TranslateErr<E> {
377+
/// Enum used to capture errors from the [`Translator`] trait as well as
378+
/// context errors from the translated structure.
379+
/// The errors occurred in translation are captured in the [`TranslateErr::TranslatorErr`]
380+
/// while the errors in the translated structure are captured in the [`TranslateErr::OuterError`]
381+
///
382+
/// As of taproot upgrade: The following rules apply to the translation of descriptors:
383+
/// - Legacy/Bare does not allow x_only keys
384+
/// - SegwitV0 does not allow uncompressed keys and x_only keys
385+
/// - Tapscript does not allow uncompressed keys
386+
/// - Translating into multi-path descriptors should have same number of path
387+
/// for all the keys in the descriptor
388+
///
389+
/// # Errors
390+
///
391+
/// This function will return an error if the Error is OutError.
392+
pub fn try_into_translator_err(self) -> Result<E, Self> {
393+
if let Self::TranslatorErr(v) = self {
394+
Ok(v)
395+
} else {
396+
Err(self)
397+
}
398+
}
399+
}
400+
401+
impl<E> From<E> for TranslateErr<E> {
402+
fn from(v: E) -> Self {
403+
Self::TranslatorErr(v)
404+
}
405+
}
406+
407+
// Required for unwrap
408+
impl<E: fmt::Debug> fmt::Debug for TranslateErr<E> {
409+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410+
match self {
411+
Self::TranslatorErr(e) => write!(f, "TranslatorErr({:?})", e),
412+
Self::OuterError(e) => write!(f, "OuterError({:?})", e),
413+
}
414+
}
415+
}
416+
366417
/// Converts a descriptor using abstract keys to one using specific keys. Uses translator `t` to do
367418
/// the actual translation function calls.
368419
pub trait TranslatePk<P, Q>
@@ -375,7 +426,7 @@ where
375426

376427
/// Translates a struct from one generic to another where the translations
377428
/// for Pk are provided by the given [`Translator`].
378-
fn translate_pk<T, E>(&self, translator: &mut T) -> Result<Self::Output, E>
429+
fn translate_pk<T, E>(&self, translator: &mut T) -> Result<Self::Output, TranslateErr<E>>
379430
where
380431
T: Translator<P, Q, E>;
381432
}

0 commit comments

Comments
 (0)