Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Witness::p2wpkh constructor #2084

Merged
merged 2 commits into from
Sep 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 26 additions & 7 deletions bitcoin/src/blockdata/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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")
];
Expand Down