Add `ecdsa::SerializedSignature`
`Signature` only supported serialization into `Vec` which required a heap allocation as well as prevented statically proving maximum length. Adding a specialized type that holds a byte array and size solves this. The solution is very similar to `secp256k1::ecdsa::SerializedSignature`. The difference is that serialized signature in this crate contains sighash bytes flag while in `secp256k1` it doesn't.
This commit is contained in:
parent
26fc4152ec
commit
8fedbcbf13
|
@ -9,12 +9,15 @@ use core::str::FromStr;
|
|||
use core::{fmt, iter};
|
||||
|
||||
use bitcoin_internals::write_err;
|
||||
use bitcoin_internals::hex::display::DisplayHex;
|
||||
use secp256k1;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::hashes::hex::{self, FromHex};
|
||||
use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
|
||||
|
||||
const MAX_SIG_LEN: usize = 73;
|
||||
|
||||
/// An ECDSA signature with the corresponding hash type.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
@ -47,6 +50,23 @@ impl Signature {
|
|||
}
|
||||
|
||||
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format).
|
||||
///
|
||||
/// This does **not** perform extra heap allocation.
|
||||
pub fn serialize(&self) -> SerializedSignature {
|
||||
let mut buf = [0u8; MAX_SIG_LEN];
|
||||
let signature = self.sig.serialize_der();
|
||||
buf[..signature.len()].copy_from_slice(&signature);
|
||||
buf[signature.len()] = self.hash_ty as u8;
|
||||
SerializedSignature {
|
||||
data: buf,
|
||||
len: signature.len() + 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format) into `Vec`.
|
||||
///
|
||||
/// Note: this performs an extra heap allocation, you might prefer the
|
||||
/// [`serialize`](Self::serialize) method instead.
|
||||
pub fn to_vec(self) -> Vec<u8> {
|
||||
// TODO: add support to serialize to a writer to SerializedSig
|
||||
self.sig.serialize_der()
|
||||
|
@ -77,6 +97,116 @@ impl FromStr for Signature {
|
|||
}
|
||||
}
|
||||
|
||||
/// Holds signature serialized in-line (not in `Vec`).
|
||||
///
|
||||
/// This avoids allocation and allows proving maximum size of the signature (73 bytes).
|
||||
/// The type can be used largely as a byte slice. It implements all standard traits one would
|
||||
/// expect and has familiar methods.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SerializedSignature {
|
||||
data: [u8; MAX_SIG_LEN],
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl SerializedSignature {
|
||||
/// Returns an iterator over bytes of the signature.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> core::slice::Iter<'_, u8> {
|
||||
self.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Deref for SerializedSignature {
|
||||
type Target = [u8];
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data[..self.len]
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for SerializedSignature {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.data[..self.len]
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for SerializedSignature {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for SerializedSignature {
|
||||
#[inline]
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl core::borrow::Borrow<[u8]> for SerializedSignature {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl core::borrow::BorrowMut<[u8]> for SerializedSignature {
|
||||
#[inline]
|
||||
fn borrow_mut(&mut self) -> &mut [u8] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SerializedSignature {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) }
|
||||
}
|
||||
|
||||
impl fmt::Display for SerializedSignature {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
|
||||
}
|
||||
|
||||
impl fmt::LowerHex for SerializedSignature {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(&(**self).as_hex(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::UpperHex for SerializedSignature {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::UpperHex::fmt(&(**self).as_hex(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SerializedSignature {
|
||||
#[inline]
|
||||
fn eq(&self, other: &SerializedSignature) -> bool { **self == **other }
|
||||
}
|
||||
|
||||
impl Eq for SerializedSignature {}
|
||||
|
||||
impl core::hash::Hash for SerializedSignature {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
core::hash::Hash::hash(&**self, state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a SerializedSignature {
|
||||
type IntoIter = core::slice::Iter<'a, u8>;
|
||||
type Item = &'a u8;
|
||||
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
(*self).iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// A key-related error.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
#[non_exhaustive]
|
||||
|
|
Loading…
Reference in New Issue