sapio_bitcoin/util/
ecdsa.rs

1// Rust Bitcoin Library
2// Written in 2014 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! ECDSA Bitcoin signatures.
16//!
17//! This module provides ECDSA signatures used Bitcoin that can be roundtrip (de)serialized.
18
19use prelude::*;
20use core::str::FromStr;
21use core::{fmt, iter};
22use hashes::hex::{self, FromHex};
23use blockdata::transaction::NonStandardSighashType;
24use secp256k1;
25use EcdsaSighashType;
26
27/// An ECDSA signature with the corresponding hash type.
28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30pub struct EcdsaSig {
31    /// The underlying ECDSA Signature
32    pub sig: secp256k1::ecdsa::Signature,
33    /// The corresponding hash type
34    pub hash_ty: EcdsaSighashType,
35}
36
37impl EcdsaSig {
38    /// Constructs ECDSA bitcoin signature for [`EcdsaSighashType::All`]
39    pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> EcdsaSig {
40        EcdsaSig {
41            sig,
42            hash_ty: EcdsaSighashType::All
43        }
44    }
45
46    /// Deserialize from slice following the standardness rules for [`EcdsaSighashType`]
47    pub fn from_slice(sl: &[u8]) -> Result<Self, EcdsaSigError> {
48        let (hash_ty, sig) = sl.split_last()
49            .ok_or(EcdsaSigError::EmptySignature)?;
50        let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32)
51            .map_err(|_| EcdsaSigError::NonStandardSighashType(*hash_ty as u32))?;
52        let sig = secp256k1::ecdsa::Signature::from_der(sig)
53            .map_err(EcdsaSigError::Secp256k1)?;
54        Ok(EcdsaSig { sig, hash_ty })
55    }
56
57    /// Serialize EcdsaSig
58    pub fn to_vec(&self) -> Vec<u8> {
59        // TODO: add support to serialize to a writer to SerializedSig
60        self.sig.serialize_der()
61            .iter().map(|x| *x)
62            .chain(iter::once(self.hash_ty as u8))
63            .collect()
64    }
65}
66
67impl fmt::Display for EcdsaSig {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        hex::format_hex(&self.sig.serialize_der(), f)?;
70        hex::format_hex(&[self.hash_ty as u8], f)
71    }
72}
73
74impl FromStr for EcdsaSig {
75    type Err = EcdsaSigError;
76
77    fn from_str(s: &str) -> Result<Self, Self::Err> {
78        let bytes = Vec::from_hex(s)?;
79        let (sighash_byte, signature) = bytes.split_last()
80            .ok_or(EcdsaSigError::EmptySignature)?;
81        Ok(EcdsaSig {
82            sig: secp256k1::ecdsa::Signature::from_der(signature)?,
83            hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)?
84        })
85    }
86}
87
88/// A key-related error.
89#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
90pub enum EcdsaSigError {
91    /// Hex encoding error
92    HexEncoding(hex::Error),
93    /// Base58 encoding error
94    NonStandardSighashType(u32),
95    /// Empty Signature
96    EmptySignature,
97    /// secp256k1-related error
98    Secp256k1(secp256k1::Error),
99}
100
101
102impl fmt::Display for EcdsaSigError {
103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104        match *self {
105            EcdsaSigError::NonStandardSighashType(hash_ty) =>
106                write!(f, "Non standard signature hash type {}", hash_ty),
107            EcdsaSigError::Secp256k1(ref e) =>
108                write!(f, "Invalid Ecdsa signature: {}", e),
109            EcdsaSigError::EmptySignature =>
110                write!(f, "Empty ECDSA signature"),
111            EcdsaSigError::HexEncoding(e) => write!(f, "EcdsaSig hex encoding error: {}", e)
112        }
113    }
114}
115
116#[cfg(feature = "std")]
117#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
118impl ::std::error::Error for EcdsaSigError {}
119
120impl From<secp256k1::Error> for EcdsaSigError {
121    fn from(e: secp256k1::Error) -> EcdsaSigError {
122        EcdsaSigError::Secp256k1(e)
123    }
124}
125
126impl From<NonStandardSighashType> for EcdsaSigError {
127    fn from(err: NonStandardSighashType) -> Self {
128        EcdsaSigError::NonStandardSighashType(err.0)
129    }
130}
131
132impl From<hex::Error> for EcdsaSigError {
133    fn from(err: hex::Error) -> Self {
134        EcdsaSigError::HexEncoding(err)
135    }
136}