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 core::{fmt, iter};
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
use bitcoin_internals::hex::display::DisplayHex;
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::hashes::hex::{self, FromHex};
|
use crate::hashes::hex::{self, FromHex};
|
||||||
use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
|
use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
|
||||||
|
|
||||||
|
const MAX_SIG_LEN: usize = 73;
|
||||||
|
|
||||||
/// An ECDSA signature with the corresponding hash type.
|
/// An ECDSA signature with the corresponding hash type.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -47,6 +50,23 @@ impl Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format).
|
/// 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> {
|
pub fn to_vec(self) -> Vec<u8> {
|
||||||
// TODO: add support to serialize to a writer to SerializedSig
|
// TODO: add support to serialize to a writer to SerializedSig
|
||||||
self.sig.serialize_der()
|
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.
|
/// A key-related error.
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|
Loading…
Reference in New Issue