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:
Martin Habovstiak 2023-02-18 12:31:07 +01:00
parent 26fc4152ec
commit 8fedbcbf13
1 changed files with 130 additions and 0 deletions

View File

@ -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]