diff --git a/.gitignore b/.gitignore index 93426a2c..bd1795fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,3 @@ Cargo.lock #fuzz fuzz/hfuzz_target fuzz/hfuzz_workspace - -#IntelliJ project files -.idea -*.iml diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs index 2837855b..f8bf549a 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -18,6 +18,16 @@ use std::fmt; use blockdata::transaction::Transaction; use util::psbt::raw; +use hashes; + +#[derive(Debug)] +/// Enum for marking psbt hash error +pub enum PsbtHash { + Ripemd, + Sha256, + Hash160, + Hash256, +} /// Ways that a Partially Signed Transaction might fail. #[derive(Debug)] pub enum Error { @@ -48,6 +58,17 @@ pub enum Error { }, /// Unable to parse as a standard SigHash type. NonStandardSigHashType(u32), + /// Parsing errors from bitcoin_hashes + HashParseError(hashes::Error), + /// The pre-image must hash to the correponding psbt hash + InvalidPreimageHashPair { + /// Hash-type + hash_type: PsbtHash, + /// Pre-image + preimage: Vec, + /// Hash value + hash: Vec, + } } impl fmt::Display for Error { @@ -65,8 +86,20 @@ impl fmt::Display for Error { f.write_str("partially signed transactions must have an unsigned transaction") } Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"), + Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e), + Error::InvalidPreimageHashPair{ref preimage, ref hash, ref hash_type} => { + // directly using debug forms of psbthash enums + write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash ) + } } } } impl error::Error for Error {} + +#[doc(hidden)] +impl From for Error { + fn from(e: hashes::Error) -> Error { + Error::HashParseError(e) + } +} diff --git a/src/util/psbt/macros.rs b/src/util/psbt/macros.rs index 9c3bcab0..9b3987a7 100644 --- a/src/util/psbt/macros.rs +++ b/src/util/psbt/macros.rs @@ -130,6 +130,7 @@ macro_rules! impl_psbt_insert_pair { }; } + #[cfg_attr(rustfmt, rustfmt_skip)] macro_rules! impl_psbt_get_pair { ($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>|<$unkeyed_value_type:ty>)) => { @@ -155,3 +156,33 @@ macro_rules! impl_psbt_get_pair { } }; } + +// macros for serde of hashes +macro_rules! impl_psbt_hash_de_serialize { + ($hash_type:ty) => { + impl_psbt_hash_serialize!($hash_type); + impl_psbt_hash_deserialize!($hash_type); + }; +} + +macro_rules! impl_psbt_hash_deserialize { + ($hash_type:ty) => { + impl $crate::util::psbt::serialize::Deserialize for $hash_type { + fn deserialize(bytes: &[u8]) -> Result { + <$hash_type>::from_slice(&bytes[..]).map_err(|e| { + $crate::util::psbt::Error::from(e).into() + }) + } + } + }; +} + +macro_rules! impl_psbt_hash_serialize { + ($hash_type:ty) => { + impl $crate::util::psbt::serialize::Serialize for $hash_type { + fn serialize(&self) -> Vec { + self.into_inner().to_vec() + } + } + }; +} diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index 4481f755..240b1701 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -12,18 +12,19 @@ // If not, see . // -use std::collections::BTreeMap; +use std::collections::btree_map::{Entry, BTreeMap}; use blockdata::script::Script; use blockdata::transaction::{SigHashType, Transaction, TxOut}; use consensus::encode; use util::bip32::KeySource; +use hashes::{self, hash160, ripemd160, sha256, sha256d}; use util::key::PublicKey; use util::psbt; use util::psbt::map::Map; use util::psbt::raw; -use util::psbt::Error; - +use util::psbt::serialize::Deserialize; +use util::psbt::{Error, error}; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq)] @@ -55,6 +56,15 @@ pub struct Input { /// The finalized, fully-constructed scriptWitness with signatures and any /// other scripts necessary for this input to pass validation. pub final_script_witness: Option>>, + /// TODO: Proof of reserves commitment + /// RIPEMD hash to preimage map + pub ripemd_preimages: BTreeMap>, + /// SHA256 hash to preimage map + pub sha256_preimages: BTreeMap>, + /// HSAH160 hash to preimage map + pub hash160_preimages: BTreeMap>, + /// HAS256 hash to preimage map + pub hash256_preimages: BTreeMap>, /// Unknown key-value pairs for this input. pub unknown: BTreeMap>, } @@ -117,10 +127,26 @@ impl Map for Input { self.hd_keypaths <= | } } - _ => match self.unknown.entry(raw_key) { - ::std::collections::btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, - ::std::collections::btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + 10u8 => { + psbt_insert_hash_pair(&mut self.ripemd_preimages, raw_key, raw_value, error::PsbtHash::Ripemd)?; } + 11u8 => { + psbt_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsbtHash::Sha256)?; + } + 12u8 => { + psbt_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsbtHash::Hash160)?; + } + 13u8 => { + psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?; + } + _ => match self.unknown.entry(raw_key) { + ::std::collections::btree_map::Entry::Vacant(empty_key) => { + empty_key.insert(raw_value); + } + ::std::collections::btree_map::Entry::Occupied(k) => { + return Err(Error::DuplicateKey(k.key().clone()).into()) + } + }, } Ok(()) @@ -165,6 +191,22 @@ impl Map for Input { rv.push(self.final_script_witness as <8u8, _>|