diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 33e3685d..1724128a 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -29,6 +29,8 @@ use hashes::{Hash, hash160}; use hash_types::{PubkeyHash, WPubkeyHash}; use util::base58; use util::key::Error; +use blockdata::transaction::SigHashType; + /// A Bitcoin ECDSA public key #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -413,6 +415,72 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey { } } +/// An ECDSA signature with the corresponding hash type. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct EcdsaSig { + /// The underlying ECDSA Signature + pub sig: secp256k1::Signature, + /// The corresponding hash type + pub hash_ty: SigHashType, +} + +impl EcdsaSig { + + /// Deserialize from slice + pub fn from_slice(sl: &[u8]) -> Result { + let (hash_ty, sig) = sl.split_last() + .ok_or(EcdsaSigError::EmptySignature)?; + let hash_ty = SigHashType::from_u32_standard(*hash_ty as u32) + .map_err(|_| EcdsaSigError::NonStandardSigHashType(*hash_ty))?; + let sig = secp256k1::Signature::from_der(sig) + .map_err(EcdsaSigError::Secp256k1)?; + Ok(EcdsaSig { sig, hash_ty }) + } + + /// Serialize EcdsaSig + pub fn to_vec(&self) -> Vec { + // TODO: add support to serialize to a writer to SerializedSig + let mut ser_sig = self.sig.serialize_der().to_vec(); + ser_sig.push(self.hash_ty.as_u32() as u8); + ser_sig + } +} + +/// A key-related error. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum EcdsaSigError { + /// Base58 encoding error + NonStandardSigHashType(u8), + /// Empty Signature + EmptySignature, + /// secp256k1-related error + Secp256k1(secp256k1::Error), +} + + +impl fmt::Display for EcdsaSigError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + EcdsaSigError::NonStandardSigHashType(hash_ty) => + write!(f, "Non standard signature hash type {}", hash_ty), + EcdsaSigError::Secp256k1(ref e) => + write!(f, "Invalid Ecdsa signature: {}", e), + EcdsaSigError::EmptySignature => + write!(f, "Empty ECDSA signature"), + } + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl ::std::error::Error for EcdsaSigError {} + +impl From for EcdsaSigError { + fn from(e: secp256k1::Error) -> EcdsaSigError { + EcdsaSigError::Secp256k1(e) + } +} + #[cfg(test)] mod tests { use io;