diff --git a/src/lib.rs b/src/lib.rs index dd0888624..50a6d3f03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -775,6 +775,8 @@ pub enum Error { TrNoScriptCode, /// No explicit script for Tr descriptors TrNoExplicitScript, + /// Parsing error for single key + SingleKeyParseError, } // https://github.com/sipa/miniscript/pull/5 for discussion on this number @@ -848,6 +850,7 @@ impl fmt::Display for Error { Error::TaprootSpendInfoUnavialable => write!(f, "Taproot Spend Info not computed."), Error::TrNoScriptCode => write!(f, "No script code for Tr descriptors"), Error::TrNoExplicitScript => write!(f, "No script code for Tr descriptors"), + Error::SingleKeyParseError => f.write_str("not able to parse the single key"), } } } @@ -888,6 +891,7 @@ impl error::Error for Error { | BareDescriptorAddr | TaprootSpendInfoUnavialable | TrNoScriptCode + | SingleKeyParseError | TrNoExplicitScript => None, Script(e) => Some(e), AddrError(e) => Some(e), diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 9d50d63d1..f835364ce 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -41,6 +41,7 @@ pub mod hash256; pub mod iter; pub mod lex; pub mod limits; +pub mod musig_key; pub mod satisfy; pub mod types; diff --git a/src/miniscript/musig_key.rs b/src/miniscript/musig_key.rs new file mode 100644 index 000000000..357fdfa97 --- /dev/null +++ b/src/miniscript/musig_key.rs @@ -0,0 +1,100 @@ +//! Support for multi-signature keys +use core::fmt; +use core::str::FromStr; + +use crate::expression::{FromTree, Tree}; +use crate::prelude::*; +use crate::{Error, MiniscriptKey}; + +#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] +/// Enum for representing musig keys in miniscript +pub enum KeyExpr { + /// Single-key (e.g pk(a), here 'a' is a single key) + SingleKey(Pk), + + /// Collection of keys in used for musig-signature + MuSig(Vec>), +} + +impl FromTree for KeyExpr { + fn from_tree(tree: &Tree) -> Result, Error> { + if tree.name == "musig" { + let mut key_expr_vec = vec![]; + for sub_tree in tree.args.iter() { + let temp_res = KeyExpr::::from_tree(sub_tree)?; + key_expr_vec.push(temp_res); + } + Ok(KeyExpr::MuSig(key_expr_vec)) + } else { + let single_key = Pk::from_str(tree.name).map_err(|_| Error::SingleKeyParseError)?; + Ok(KeyExpr::SingleKey(single_key)) + } + } +} + +impl FromStr for KeyExpr { + type Err = Error; + fn from_str(s: &str) -> Result { + let (key_tree, _) = Tree::from_slice(s).unwrap(); + FromTree::from_tree(&key_tree) + } +} + +impl fmt::Debug for KeyExpr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + KeyExpr::SingleKey(ref pk) => write!(f, "{:?}", pk), + KeyExpr::MuSig(ref my_vec) => { + write!(f, "musig(")?; + let len = my_vec.len(); + for (index, k) in my_vec.iter().enumerate() { + if index == len - 1 { + write!(f, "{:?}", k)?; + } else { + write!(f, "{:?}", k)?; + } + } + f.write_str(")") + } + } + } +} + +impl fmt::Display for KeyExpr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + KeyExpr::SingleKey(ref pk) => write!(f, "{}", pk), + KeyExpr::MuSig(ref my_vec) => { + write!(f, "musig(")?; + let len = my_vec.len(); + for (index, k) in my_vec.iter().enumerate() { + if index == len - 1 { + write!(f, "{}", k)?; + } else { + write!(f, "{},", k)?; + } + } + f.write_str(")") + } + } + } +} +#[cfg(test)] +mod tests { + use super::*; + + fn test_one(musig_key: &str) { + let pk = KeyExpr::::from_str(musig_key).unwrap(); + println!("{}", pk); + dbg!(&pk); + assert_eq!(musig_key, format!("{}", pk)) + } + + #[test] + fn test_from_str_and_fmt() { + test_one("musig(A,B,musig(C,musig(D,E)))"); + test_one("musig(A)"); + test_one("A"); + test_one("musig(,,)"); + } +}