Add functionality to serialize signatures to a writer

Serializing the ecdsa and taproot `Signature` straight to a writer is a
useful thing to be able to do.

To both ECDSA and Taproot types:

- Add `SerializedSignature::to_writer`
- Add `Signature::serialize_to_writer`

Remove TODO comments from code.
This commit is contained in:
Tobin C. Harding 2024-01-23 19:10:58 +11:00
parent d08d3efdfa
commit 3cfd746bbc
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
3 changed files with 48 additions and 2 deletions

View File

@ -9,6 +9,7 @@ use core::{fmt, iter};
use hex::FromHex; use hex::FromHex;
use internals::write_err; use internals::write_err;
use io::Write;
use secp256k1; use secp256k1;
use crate::prelude::*; use crate::prelude::*;
@ -58,7 +59,6 @@ impl Signature {
/// Note: this performs an extra heap allocation, you might prefer the /// Note: this performs an extra heap allocation, you might prefer the
/// [`serialize`](Self::serialize) method instead. /// [`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
self.signature self.signature
.serialize_der() .serialize_der()
.iter() .iter()
@ -66,6 +66,13 @@ impl Signature {
.chain(iter::once(self.sighash_type as u8)) .chain(iter::once(self.sighash_type as u8))
.collect() .collect()
} }
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format) to a `writer`.
#[inline]
pub fn serialize_to_writer<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
let sig = self.serialize();
sig.write_to(writer)
}
} }
impl fmt::Display for Signature { impl fmt::Display for Signature {
@ -105,6 +112,12 @@ impl SerializedSignature {
/// Returns an iterator over bytes of the signature. /// Returns an iterator over bytes of the signature.
#[inline] #[inline]
pub fn iter(&self) -> core::slice::Iter<'_, u8> { self.into_iter() } pub fn iter(&self) -> core::slice::Iter<'_, u8> { self.into_iter() }
/// Writes this serialized signature to a `writer`.
#[inline]
pub fn write_to<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
writer.write_all(self)
}
} }
impl core::ops::Deref for SerializedSignature { impl core::ops::Deref for SerializedSignature {
@ -239,3 +252,22 @@ impl From<NonStandardSighashTypeError> for Error {
impl From<hex::HexToBytesError> for Error { impl From<hex::HexToBytesError> for Error {
fn from(err: hex::HexToBytesError) -> Self { Error::Hex(err) } fn from(err: hex::HexToBytesError) -> Self { Error::Hex(err) }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn write_serialized_signature() {
let hex = "3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45";
let sig = Signature {
signature: secp256k1::ecdsa::Signature::from_str(hex).unwrap(),
sighash_type: EcdsaSighashType::All,
};
let mut buf = vec![];
sig.serialize_to_writer(&mut buf).expect("write failed");
assert_eq!(sig.to_vec(), buf)
}
}

View File

@ -8,6 +8,7 @@
use core::fmt; use core::fmt;
use internals::write_err; use internals::write_err;
use io::Write;
use crate::prelude::*; use crate::prelude::*;
use crate::sighash::{InvalidSighashTypeError, TapSighashType}; use crate::sighash::{InvalidSighashTypeError, TapSighashType};
@ -47,7 +48,6 @@ impl Signature {
/// ///
/// Note: this allocates on the heap, prefer [`serialize`](Self::serialize) if vec is not needed. /// Note: this allocates on the heap, prefer [`serialize`](Self::serialize) if vec is not needed.
pub fn to_vec(self) -> Vec<u8> { pub fn to_vec(self) -> Vec<u8> {
// TODO: add support to serialize to a writer to SerializedSig
let mut ser_sig = self.signature.as_ref().to_vec(); let mut ser_sig = self.signature.as_ref().to_vec();
if self.sighash_type == TapSighashType::Default { if self.sighash_type == TapSighashType::Default {
// default sighash type, don't add extra sighash byte // default sighash type, don't add extra sighash byte
@ -57,6 +57,13 @@ impl Signature {
ser_sig ser_sig
} }
/// Serializes the signature to `writer`.
#[inline]
pub fn serialize_to_writer<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
let sig = self.serialize();
sig.write_to(writer)
}
/// Serializes the signature (without heap allocation) /// Serializes the signature (without heap allocation)
/// ///
/// This returns a type with an API very similar to that of `Box<[u8]>`. /// This returns a type with an API very similar to that of `Box<[u8]>`.

View File

@ -10,6 +10,7 @@ use core::convert::TryFrom;
use core::{fmt, ops}; use core::{fmt, ops};
pub use into_iter::IntoIter; pub use into_iter::IntoIter;
use io::Write;
use super::{SigFromSliceError, Signature}; use super::{SigFromSliceError, Signature};
@ -166,6 +167,12 @@ impl SerializedSignature {
/// (this serializes it) /// (this serializes it)
#[inline] #[inline]
pub fn from_signature(sig: &Signature) -> SerializedSignature { sig.serialize() } pub fn from_signature(sig: &Signature) -> SerializedSignature { sig.serialize() }
/// Writes this serialized signature to a `writer`.
#[inline]
pub fn write_to<W: Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
writer.write_all(self)
}
} }
/// Separate mod to prevent outside code from accidentally breaking invariants. /// Separate mod to prevent outside code from accidentally breaking invariants.