Merge rust-bitcoin/rust-bitcoin#2084: Add `Witness::p2wpkh` constructor

5901d35095 Add push_p2wpkh function on Witness (Tobin C. Harding)
8cd409d561 Deprecate push_bitcoin_signature (Tobin C. Harding)

Pull request description:

  In order to create the witness to spend p2wpkh output one must create a `Witness` that includes the signature and the pubkey, we should have a function for this.

  ## Notes
  The PR originally added a `push_p2wphk` method, this is now instead a constrcutor `Witness:p2wpkh` (after review discussion below).

  - Patch 1 changes `push_bitcoin_signature` to take an `ecdsa::Sigtnture` instead of an `ecdsa::SerializedSignature`
  - Patch 2 takes a `secp256k1::PublicKey` removing the need for an error path (discussed below).

ACKs for top commit:
  sanket1729:
    ACK 5901d35095
  apoelstra:
    ACK 5901d35095

Tree-SHA512: 646014d97daafbf0909106d8990debaf481ac6f3578f0ddf232d739c3e2d55ae1d0275abe5a4a1db1c5c192c8c5f0b5546fc65aac37b91a3729db881c5ad3dec
This commit is contained in:
Andrew Poelstra 2023-09-26 13:01:02 +00:00
commit 1c29dd97ce
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
1 changed files with 26 additions and 7 deletions

View File

@ -9,10 +9,9 @@ use core::convert::TryInto;
use core::fmt;
use core::ops::Index;
use secp256k1::ecdsa;
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
use crate::consensus::{Decodable, Encodable, WriteExt};
use crate::crypto::ecdsa;
use crate::io::{self, Read, Write};
use crate::prelude::*;
use crate::sighash::EcdsaSighashType;
@ -237,6 +236,19 @@ impl Witness {
/// Creates a new empty [`Witness`].
pub fn new() -> Self { Witness::default() }
/// Creates a witness required to spend a P2WPKH output.
///
/// The witness will be made up of the DER encoded signature + sighash_type followed by the
/// serialized public key. Also useful for spending a P2SH-P2WPKH output.
///
/// It is expected that `pubkey` is related to the secret key used to create `signature`.
pub fn p2wpkh(signature: &ecdsa::Signature, pubkey: &secp256k1::PublicKey) -> Witness {
let mut witness = Witness::new();
witness.push_slice(&signature.serialize());
witness.push_slice(&pubkey.serialize());
witness
}
/// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
let witness_elements = slice.len();
@ -321,9 +333,10 @@ impl Witness {
/// Pushes a DER-encoded ECDSA signature with a signature hash type as a new element on the
/// witness, requires an allocation.
#[deprecated(since = "0.30.0", note = "use push_ecdsa_signature instead")]
pub fn push_bitcoin_signature(
&mut self,
signature: &ecdsa::SerializedSignature,
signature: &secp256k1::ecdsa::SerializedSignature,
hash_type: EcdsaSighashType,
) {
// Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73
@ -333,6 +346,13 @@ impl Witness {
self.push(&sig[..signature.len() + 1]);
}
/// Pushes, as a new element on the witness, an ECDSA signature.
///
/// Pushes the DER encoded signature + sighash_type, requires an allocation.
pub fn push_ecdsa_signature(&mut self, signature: &ecdsa::Signature) {
self.push_slice(&signature.serialize())
}
fn element_at(&self, index: usize) -> Option<&[u8]> {
let varint = VarInt::consensus_decode(&mut &self.content[index..]).ok()?;
let start = index + varint.len();
@ -525,8 +545,6 @@ impl From<Vec<&[u8]>> for Witness {
#[cfg(test)]
mod test {
use secp256k1::ecdsa;
use super::*;
use crate::consensus::{deserialize, serialize};
use crate::internal_macros::hex;
@ -624,9 +642,10 @@ mod test {
// The very first signature in block 734,958
let sig_bytes =
hex!("304402207c800d698f4b0298c5aac830b822f011bb02df41eb114ade9a6702f364d5e39c0220366900d2a60cab903e77ef7dd415d46509b1f78ac78906e3296f495aa1b1b541");
let sig = ecdsa::Signature::from_der(&sig_bytes).unwrap();
let sig = secp256k1::ecdsa::Signature::from_der(&sig_bytes).unwrap();
let mut witness = Witness::default();
witness.push_bitcoin_signature(&sig.serialize_der(), EcdsaSighashType::All);
let signature = ecdsa::Signature { sig, hash_ty: EcdsaSighashType::All };
witness.push_ecdsa_signature(&signature);
let expected_witness = vec![hex!(
"304402207c800d698f4b0298c5aac830b822f011bb02df41eb114ade9a6702f364d5e39c0220366900d2a60cab903e77ef7dd415d46509b1f78ac78906e3296f495aa1b1b54101")
];