Merge rust-bitcoin/rust-bitcoin#2392: Add functionality to serialize signatures to a writer

3cfd746bbc Add functionality to serialize signatures to a writer (Tobin C. Harding)

Pull request description:

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

  Add `to_writer` to both `SerializedSignature`s and also to the `Signature`s (calling through to `SerializedSignature`).

  Remove TODO comments from code.

ACKs for top commit:
  Kixunil:
    ACK 3cfd746bbc

Tree-SHA512: 82eb6d42c7b327cdfe5e89348890e45ea39c664420f7ea17d7826a5c388c7aaae917b1334e3f3df645fc4a81a11b59d97c7d6958e99077fbd67193e2a588f2eb
This commit is contained in:
Andrew Poelstra 2024-01-24 18:05:33 +00:00
commit 2f7d6451f8
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
3 changed files with 48 additions and 2 deletions

View File

@ -9,6 +9,7 @@ use core::{fmt, iter};
use hex::FromHex;
use internals::write_err;
use io::Write;
use secp256k1;
use crate::prelude::*;
@ -58,7 +59,6 @@ impl Signature {
/// 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.signature
.serialize_der()
.iter()
@ -66,6 +66,13 @@ impl Signature {
.chain(iter::once(self.sighash_type as u8))
.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 {
@ -105,6 +112,12 @@ impl SerializedSignature {
/// Returns an iterator over bytes of the signature.
#[inline]
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 {
@ -239,3 +252,22 @@ impl From<NonStandardSighashTypeError> for Error {
impl From<hex::HexToBytesError> for Error {
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 internals::write_err;
use io::Write;
use crate::prelude::*;
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.
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();
if self.sighash_type == TapSighashType::Default {
// default sighash type, don't add extra sighash byte
@ -57,6 +57,13 @@ impl Signature {
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)
///
/// 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};
pub use into_iter::IntoIter;
use io::Write;
use super::{SigFromSliceError, Signature};
@ -166,6 +167,12 @@ impl SerializedSignature {
/// (this serializes it)
#[inline]
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.