Skip to content

Commit

Permalink
miniscript: add an optional Pk to PkH nodes
Browse files Browse the repository at this point in the history
This allows to access the actual public key behind the pubkey_hash. This
can be used to derive public keys behind pubkey_hash in Miniscripts with
extended public keys by modifying the translation function.

However, the preimage is not available when parsing Miniscript from
Script so it is inherently Option'al.

Signed-off-by: Antoine Poinsot <darosior@protonmail.com>
  • Loading branch information
darosior committed Sep 25, 2020
1 parent 4538c1b commit 80a76d7
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/descriptor/satisfied_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ where
return res;
}
}
Terminal::PkH(ref pkh) => {
Terminal::PkH(_, ref pkh) => {
debug_assert_eq!(node_state.n_evaluated, 0);
debug_assert_eq!(node_state.n_satisfied, 0);
let res = self.stack.evaluate_pkh(&mut self.verify_sig, pkh);
Expand Down
21 changes: 12 additions & 9 deletions src/miniscript/astelem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
{
let frag = match *self {
Terminal::PkK(ref p) => Terminal::PkK(translatefpk(p)?),
Terminal::PkH(ref p) => Terminal::PkH(translatefpkh(p)?),
Terminal::PkH(ref pk, ref pkh) => match pk {
Some(pk) => Terminal::PkH(Some(translatefpk(pk)?), translatefpkh(pkh)?),
None => Terminal::PkH(None, translatefpkh(pkh)?),
},
Terminal::After(n) => Terminal::After(n),
Terminal::Older(n) => Terminal::Older(n),
Terminal::Sha256(x) => Terminal::Sha256(x),
Expand Down Expand Up @@ -205,7 +208,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
} else {
match *self {
Terminal::PkK(ref pk) => write!(f, "pk_k({:?})", pk),
Terminal::PkH(ref pkh) => write!(f, "pk_h({:?})", pkh),
Terminal::PkH(_, ref pkh) => write!(f, "pk_h({:?})", pkh),
Terminal::After(t) => write!(f, "after({})", t),
Terminal::Older(t) => write!(f, "older({})", t),
Terminal::Sha256(h) => write!(f, "sha256({})", h),
Expand Down Expand Up @@ -255,7 +258,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Terminal::PkK(ref pk) => write!(f, "pk_k({})", pk),
Terminal::PkH(ref pkh) => write!(f, "pk_h({})", pkh),
Terminal::PkH(_, ref pkh) => write!(f, "pk_h({})", pkh),
Terminal::After(t) => write!(f, "after({})", t),
Terminal::Older(t) => write!(f, "older({})", t),
Terminal::Sha256(h) => write!(f, "sha256({})", h),
Expand Down Expand Up @@ -308,7 +311,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
if let Terminal::PkK(ref pk) = sub.node {
// alias: pk(K) = c:pk_k(K)
return write!(f, "pk({})", pk);
} else if let Terminal::PkH(ref pkh) = sub.node {
} else if let Terminal::PkH(_, ref pkh) = sub.node {
// alias: pkh(K) = c:pk_h(K)
return write!(f, "pkh({})", pkh);
}
Expand All @@ -324,7 +327,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
Some(('c', ms)) => {
if let Terminal::PkK(ref _pk) = ms.node {
fmt::Write::write_char(f, ':')?;
} else if let Terminal::PkH(ref _pkh) = ms.node {
} else if let Terminal::PkH(_, ref _pkh) = ms.node {
fmt::Write::write_char(f, ':')?;
}
}
Expand Down Expand Up @@ -407,9 +410,9 @@ where
("pk_k", 1) => {
expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkK))
}
("pk_h", 1) => {
expression::terminal(&top.args[0], |x| Pk::Hash::from_str(x).map(Terminal::PkH))
}
("pk_h", 1) => expression::terminal(&top.args[0], |x| {
Pk::Hash::from_str(x).map(|x| Terminal::PkH(None, x))
}),
("after", 1) => expression::terminal(&top.args[0], |x| {
expression::parse_num(x).map(Terminal::After)
}),
Expand Down Expand Up @@ -570,7 +573,7 @@ impl<Pk: MiniscriptKey + ToPublicKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
pub fn encode(&self, mut builder: script::Builder) -> script::Builder {
match *self {
Terminal::PkK(ref pk) => builder.push_key(&pk.to_public_key()),
Terminal::PkH(ref hash) => builder
Terminal::PkH(_, ref hash) => builder
.push_opcode(opcodes::all::OP_DUP)
.push_opcode(opcodes::all::OP_HASH160)
.push_slice(&Pk::hash_to_hash160(&hash)[..])
Expand Down
2 changes: 1 addition & 1 deletion src/miniscript/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl ScriptContext for Legacy {
frag: &Terminal<Pk, Ctx>,
) -> Result<(), ScriptContextError> {
match *frag {
Terminal::PkH(ref _pkh) => Err(ScriptContextError::MalleablePkH),
Terminal::PkH(..) => Err(ScriptContextError::MalleablePkH),
Terminal::OrI(ref _a, ref _b) => Err(ScriptContextError::MalleableOrI),
Terminal::DupIf(ref _ms) => Err(ScriptContextError::MalleableDupIf),
_ => Ok(()),
Expand Down
3 changes: 2 additions & 1 deletion src/miniscript/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub enum Terminal<Pk: MiniscriptKey, Ctx: ScriptContext> {
/// `<key>`
PkK(Pk),
/// `DUP HASH160 <keyhash> EQUALVERIFY`
PkH(Pk::Hash),
PkH(Option<Pk>, Pk::Hash),
// timelocks
/// `n CHECKLOCKTIMEVERIFY`
After(u32),
Expand Down Expand Up @@ -240,6 +240,7 @@ pub fn parse<Ctx: ScriptContext>(
tokens,
Tk::Hash20(hash), Tk::Hash160, Tk::Dup => {
term.reduce0(Terminal::PkH(
None,
hash160::Hash::from_inner(hash)
))?
},
Expand Down
4 changes: 2 additions & 2 deletions src/miniscript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ mod tests {

let pkh_ms: Miniscript<DummyKey, Segwitv0> = Miniscript {
node: Terminal::Check(Arc::new(Miniscript {
node: Terminal::PkH(DummyKeyHash),
node: Terminal::PkH(None, DummyKeyHash),
ty: Type::from_pk_h(),
ext: types::extra_props::ExtData::from_pk_h(),
phantom: PhantomData,
Expand Down Expand Up @@ -524,7 +524,7 @@ mod tests {

let pkh_ms: Segwitv0Script = Miniscript {
node: Terminal::Check(Arc::new(Miniscript {
node: Terminal::PkH(hash),
node: Terminal::PkH(None, hash),
ty: Type::from_pk_h(),
ext: types::extra_props::ExtData::from_pk_h(),
phantom: PhantomData,
Expand Down
4 changes: 2 additions & 2 deletions src/miniscript/satisfy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ impl Satisfaction {
stack: Witness::signature(stfr, pk),
has_sig: true,
},
Terminal::PkH(ref pkh) => Satisfaction {
Terminal::PkH(_, ref pkh) => Satisfaction {
stack: Witness::pkh_signature(stfr, pkh),
has_sig: true,
},
Expand Down Expand Up @@ -760,7 +760,7 @@ impl Satisfaction {
stack: Witness::push_0(),
has_sig: false,
},
Terminal::PkH(ref pkh) => Satisfaction {
Terminal::PkH(_, ref pkh) => Satisfaction {
stack: Witness::combine(Witness::push_0(), Witness::pkh_public_key(stfr, pkh)),
has_sig: false,
},
Expand Down
4 changes: 3 additions & 1 deletion src/policy/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ where
match *policy {
Concrete::Key(ref pk) => {
insert_wrap!(AstElemExt::terminal(Terminal::PkH(
Some(pk.clone()),
pk.to_pubkeyhash().clone()
)));
insert_wrap!(AstElemExt::terminal(Terminal::PkK(pk.clone())));
Expand Down Expand Up @@ -1325,7 +1326,8 @@ mod tests {
keys[7].to_pubkeyhash()
);

assert_eq!(ms, ms_comp_res);
// We compare the Script encoding as the parsed miniscript could not detect the keys for PkHs.
assert_eq!(ms.encode(), ms_comp_res.encode());

let mut abs = policy.lift();
assert_eq!(abs.n_keys(), 8);
Expand Down
2 changes: 1 addition & 1 deletion src/policy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Terminal<Pk, Ctx> {
fn lift(&self) -> Semantic<Pk> {
match *self {
Terminal::PkK(ref pk) => Semantic::KeyHash(pk.to_pubkeyhash()),
Terminal::PkH(ref pkh) => Semantic::KeyHash(pkh.clone()),
Terminal::PkH(_, ref pkh) => Semantic::KeyHash(pkh.clone()),
Terminal::After(t) => Semantic::After(t),
Terminal::Older(t) => Semantic::Older(t),
Terminal::Sha256(h) => Semantic::Sha256(h),
Expand Down

0 comments on commit 80a76d7

Please sign in to comment.