From c1eccfde25fd4c2b19e7ec6759352b46ac246113 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 24 Sep 2024 10:27:14 +1000 Subject: [PATCH] Move Witness to primitives Move the `Witness` over to `primitives` leaving behind any method that takes or returns a `Script` or a signature. Includes addition of a feature gate to unit test. --- Cargo-minimal.lock | 4 +- Cargo-recent.lock | 4 +- bitcoin/examples/ecdsa-psbt-simple.rs | 1 + bitcoin/examples/sign-tx-segwit-v0.rs | 1 + bitcoin/examples/sign-tx-taproot.rs | 1 + bitcoin/examples/taproot-psbt-simple.rs | 1 + bitcoin/src/blockdata/witness.rs | 792 ++++-------------------- internals/Cargo.toml | 5 +- internals/src/serde.rs | 14 + primitives/Cargo.toml | 4 +- primitives/README.md | 5 + primitives/src/lib.rs | 7 +- primitives/src/witness.rs | 636 +++++++++++++++++++ 13 files changed, 785 insertions(+), 690 deletions(-) create mode 100644 primitives/src/witness.rs diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index b8f1f663a..38ae45f53 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -95,6 +95,7 @@ name = "bitcoin-internals" version = "0.4.0" dependencies = [ "bincode", + "hex-conservative", "serde", "serde_json", ] @@ -111,6 +112,7 @@ name = "bitcoin-primitives" version = "0.100.0" dependencies = [ "arbitrary", + "bincode", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -119,6 +121,7 @@ dependencies = [ "mutagen", "ordered", "serde", + "serde_json", ] [[package]] @@ -197,7 +200,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" dependencies = [ "arrayvec", - "serde", ] [[package]] diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 1b6cb85ae..8dab80e1a 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -94,6 +94,7 @@ name = "bitcoin-internals" version = "0.4.0" dependencies = [ "bincode", + "hex-conservative", "serde", "serde_json", ] @@ -110,6 +111,7 @@ name = "bitcoin-primitives" version = "0.100.0" dependencies = [ "arbitrary", + "bincode", "bitcoin-internals", "bitcoin-io", "bitcoin-units", @@ -118,6 +120,7 @@ dependencies = [ "mutagen", "ordered", "serde", + "serde_json", ] [[package]] @@ -199,7 +202,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" dependencies = [ "arrayvec", - "serde", ] [[package]] diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index 10bd5aea5..4e2ca1085 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -29,6 +29,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, Fingerprint, IntoDerivationPat use bitcoin::locktime::absolute; use bitcoin::psbt::Input; use bitcoin::secp256k1::{Secp256k1, Signing}; +use bitcoin::witness::WitnessExt as _; use bitcoin::{ consensus, transaction, Address, Amount, EcdsaSighashType, Network, OutPoint, Psbt, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, WPubkeyHash, Witness, diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index 821921ded..60ab1e551 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -6,6 +6,7 @@ use bitcoin::address::script_pubkey::ScriptBufExt as _; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing}; use bitcoin::sighash::{EcdsaSighashType, SighashCache}; +use bitcoin::witness::WitnessExt as _; use bitcoin::{ transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, WPubkeyHash, Witness, diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 36c56909c..3b55edded 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -7,6 +7,7 @@ use bitcoin::key::{Keypair, TapTweak, TweakedKeypair, UntweakedPublicKey}; use bitcoin::locktime::absolute; use bitcoin::secp256k1::{rand, Message, Secp256k1, SecretKey, Signing, Verification}; use bitcoin::sighash::{Prevouts, SighashCache, TapSighashType}; +use bitcoin::witness::WitnessExt as _; use bitcoin::{ transaction, Address, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Txid, Witness, diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index b98aba868..372c1a969 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -28,6 +28,7 @@ use bitcoin::key::UntweakedPublicKey; use bitcoin::locktime::absolute; use bitcoin::psbt::Input; use bitcoin::secp256k1::{Secp256k1, Signing}; +use bitcoin::witness::WitnessExt as _; use bitcoin::{ consensus, transaction, Address, Amount, Network, OutPoint, Psbt, ScriptBuf, Sequence, TapLeafHash, TapSighashType, Transaction, TxIn, TxOut, Txid, Witness, XOnlyPublicKey, diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs index 6ef97c366..0264f7fa7 100644 --- a/bitcoin/src/blockdata/witness.rs +++ b/bitcoin/src/blockdata/witness.rs @@ -4,11 +4,6 @@ //! //! This module contains the [`Witness`] struct and related methods to operate on it -use core::fmt; -use core::ops::Index; - -#[cfg(feature = "arbitrary")] -use arbitrary::{Arbitrary, Unstructured}; use internals::compact_size; use io::{BufRead, Write}; @@ -21,119 +16,9 @@ use crate::script::ScriptExt as _; use crate::taproot::{self, TAPROOT_ANNEX_PREFIX}; use crate::Script; -/// The Witness is the data used to unlock bitcoin since the [segwit upgrade]. -/// -/// Can be logically seen as an array of bytestrings, i.e. `Vec>`, and it is serialized on the wire -/// in that format. You can convert between this type and `Vec>` by using [`Witness::from_slice`] -/// and [`Witness::to_vec`]. -/// -/// For serialization and deserialization performance it is stored internally as a single `Vec`, -/// saving some allocations. -/// -/// [segwit upgrade]: -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Witness { - /// Contains the witness `Vec>` serialization. - /// - /// Does not include the initial varint indicating the number of elements. Each element however, - /// does include a varint indicating the element length. The number of elements is stored in - /// `witness_elements`. - /// - /// Concatenated onto the end of `content` is the index area. This is a `4 * witness_elements` - /// bytes area which stores the index of the start of each witness item. - content: Vec, - - /// The number of elements in the witness. - /// - /// Stored separately (instead of as a compact size encoding in the initial part of content) so - /// that methods like [`Witness::push`] don't have to shift the entire array. - witness_elements: usize, - - /// This is the valid index pointing to the beginning of the index area. - /// - /// Said another way, this is the total length of all witness elements serialized (without the - /// element count but with their sizes serialized as compact size). - indices_start: usize, -} - -impl fmt::Debug for Witness { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - if f.alternate() { - fmt_debug_pretty(self, f) - } else { - fmt_debug(self, f) - } - } -} - -fn fmt_debug(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - #[rustfmt::skip] - let comma_or_close = |current_index, last_index| { - if current_index == last_index { "]" } else { ", " } - }; - - f.write_str("Witness: { ")?; - write!(f, "indices: {}, ", w.witness_elements)?; - write!(f, "indices_start: {}, ", w.indices_start)?; - f.write_str("witnesses: [")?; - - let instructions = w.iter(); - match instructions.len().checked_sub(1) { - Some(last_instruction) => { - for (i, instruction) in instructions.enumerate() { - let bytes = instruction.iter(); - match bytes.len().checked_sub(1) { - Some(last_byte) => { - f.write_str("[")?; - for (j, byte) in bytes.enumerate() { - write!(f, "{:#04x}", byte)?; - f.write_str(comma_or_close(j, last_byte))?; - } - } - None => { - // This is possible because the varint is not part of the instruction (see Iter). - write!(f, "[]")?; - } - } - f.write_str(comma_or_close(i, last_instruction))?; - } - } - None => { - // Witnesses can be empty because the 0x00 var int is not stored in content. - write!(f, "]")?; - } - } - - f.write_str(" }") -} - -fn fmt_debug_pretty(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("Witness: {\n")?; - writeln!(f, " indices: {},", w.witness_elements)?; - writeln!(f, " indices_start: {},", w.indices_start)?; - f.write_str(" witnesses: [\n")?; - - for instruction in w.iter() { - f.write_str(" [")?; - for (j, byte) in instruction.iter().enumerate() { - if j > 0 { - f.write_str(", ")?; - } - write!(f, "{:#04x}", byte)?; - } - f.write_str("],\n")?; - } - - writeln!(f, " ],")?; - writeln!(f, "}}") -} - -/// An iterator returning individual witness elements. -pub struct Iter<'a> { - inner: &'a [u8], - indices_start: usize, - current_index: usize, -} +#[rustfmt::skip] // Keep public re-exports separate. +#[doc(inline)] +pub use primitives::witness::{Witness, Iter}; impl Decodable for Witness { fn consensus_decode(r: &mut R) -> Result { @@ -199,26 +84,6 @@ impl Decodable for Witness { } } -/// Correctness Requirements: value must always fit within u32 -#[inline] -fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) { - let start = start_of_indices + index * 4; - let end = start + 4; - bytes[start..end] - .copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("larger than u32"))); -} - -#[inline] -fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option { - let start = start_of_indices + index * 4; - let end = start + 4; - if end > bytes.len() { - None - } else { - Some(u32::from_ne_bytes(bytes[start..end].try_into().expect("is u32 size")) as usize) - } -} - fn resize_if_needed(vec: &mut Vec, required_len: usize) { if required_len >= vec.len() { let mut new_len = vec.len().max(1); @@ -242,401 +107,123 @@ impl Encodable for Witness { } } -impl Witness { - /// Creates a new empty [`Witness`]. - #[inline] - pub const fn new() -> Self { - Witness { content: Vec::new(), witness_elements: 0, indices_start: 0 } - } +crate::internal_macros::define_extension_trait! { + /// Extension functionality for the [`Witness`] type. + pub trait WitnessExt impl for Witness { + /// Convenience method to create an array of byte-arrays from this witness. + #[deprecated(since = "TBD", note = "use `to_bytes` instead")] + fn to_vec(&self) -> Vec> { self.to_bytes() } - /// Creates a new [`Witness`] from inner parts. - /// - /// This function leaks implementation details of the `Witness`, as such it is unstable and - /// should not be relied upon (it is primarily provided for use in `rust-bitcoin`). - /// - /// UNSTABLE: This function may change, break, or disappear in any release. - #[inline] - #[doc(hidden)] - #[allow(non_snake_case)] // Because of `__unstable`. - pub fn from_parts__unstable(content: Vec, witness_elements: usize, indices_start: usize) -> Self { - Witness { content, witness_elements, indices_start } - } - - /// 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(signature.serialize()); - witness.push(pubkey.serialize()); - witness - } - - /// Creates a witness required to do a key path spend of a P2TR output. - pub fn p2tr_key_spend(signature: &taproot::Signature) -> Witness { - let mut witness = Witness::new(); - witness.push(signature.serialize()); - witness - } - - /// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item. - pub fn from_slice>(slice: &[T]) -> Self { - let witness_elements = slice.len(); - let index_size = witness_elements * 4; - let content_size = slice - .iter() - .map(|elem| elem.as_ref().len() + compact_size::encoded_size(elem.as_ref().len())) - .sum(); - - let mut content = vec![0u8; content_size + index_size]; - let mut cursor = 0usize; - for (i, elem) in slice.iter().enumerate() { - encode_cursor(&mut content, content_size, i, cursor); - let encoded = compact_size::encode(elem.as_ref().len()); - let encoded_size = encoded.as_slice().len(); - content[cursor..cursor + encoded_size].copy_from_slice(encoded.as_slice()); - cursor += encoded_size; - content[cursor..cursor + elem.as_ref().len()].copy_from_slice(elem.as_ref()); - cursor += elem.as_ref().len(); + /// 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`. + fn p2wpkh(signature: ecdsa::Signature, pubkey: secp256k1::PublicKey) -> Witness { + let mut witness = Witness::new(); + witness.push(signature.serialize()); + witness.push(pubkey.serialize()); + witness } - Witness { witness_elements, content, indices_start: content_size } - } - - /// Convenience method to create an array of byte-arrays from this witness. - pub fn to_bytes(&self) -> Vec> { self.iter().map(|s| s.to_vec()).collect() } - - /// Convenience method to create an array of byte-arrays from this witness. - #[deprecated(since = "TBD", note = "use `to_bytes` instead")] - pub fn to_vec(&self) -> Vec> { self.to_bytes() } - - /// Returns `true` if the witness contains no element. - pub fn is_empty(&self) -> bool { self.witness_elements == 0 } - - /// Returns a struct implementing [`Iterator`]. - pub fn iter(&self) -> Iter { - Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 } - } - - /// Returns the number of elements this witness holds. - pub fn len(&self) -> usize { self.witness_elements } - - /// Returns the number of bytes this witness contributes to a transactions total size. - pub fn size(&self) -> usize { - let mut size: usize = 0; - - size += compact_size::encoded_size(self.witness_elements); - size += self - .iter() - .map(|witness_element| { - let len = witness_element.len(); - compact_size::encoded_size(len) + len - }) - .sum::(); - - size - } - - /// Clear the witness. - pub fn clear(&mut self) { - self.content.clear(); - self.witness_elements = 0; - self.indices_start = 0; - } - - /// Push a new element on the witness, requires an allocation. - pub fn push>(&mut self, new_element: T) { - self.push_slice(new_element.as_ref()); - } - - /// Push a new element slice onto the witness stack. - fn push_slice(&mut self, new_element: &[u8]) { - self.witness_elements += 1; - let previous_content_end = self.indices_start; - let encoded = compact_size::encode(new_element.len()); - let encoded_size = encoded.as_slice().len(); - let current_content_len = self.content.len(); - let new_item_total_len = encoded_size + new_element.len(); - self.content.resize(current_content_len + new_item_total_len + 4, 0); - - self.content[previous_content_end..].rotate_right(new_item_total_len); - self.indices_start += new_item_total_len; - encode_cursor( - &mut self.content, - self.indices_start, - self.witness_elements - 1, - previous_content_end, - ); - - let end_compact_size = previous_content_end + encoded_size; - self.content[previous_content_end..end_compact_size].copy_from_slice(encoded.as_slice()); - self.content[end_compact_size..end_compact_size + new_element.len()] - .copy_from_slice(new_element); - } - - /// 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(signature.serialize()) - } - - /// Note `index` is the index into the `content` vector and should be the result of calling - /// `decode_cursor`, which returns a valid index. - fn element_at(&self, index: usize) -> Option<&[u8]> { - let mut slice = &self.content[index..]; // Start of element. - let element_len = compact_size::decode_unchecked(&mut slice); - // Compact size should always fit into a u32 because of `MAX_SIZE` in Core. - // ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264 - let end = element_len as usize; - Some(&slice[..end]) - } - - /// Returns the last element in the witness, if any. - pub fn last(&self) -> Option<&[u8]> { - if self.witness_elements == 0 { - None - } else { - self.nth(self.witness_elements - 1) + /// Creates a witness required to do a key path spend of a P2TR output. + fn p2tr_key_spend(signature: &taproot::Signature) -> Witness { + let mut witness = Witness::new(); + witness.push(signature.serialize()); + witness } - } - /// Returns the second-to-last element in the witness, if any. - pub fn second_to_last(&self) -> Option<&[u8]> { - if self.witness_elements <= 1 { - None - } else { - self.nth(self.witness_elements - 2) + /// Pushes, as a new element on the witness, an ECDSA signature. + /// + /// Pushes the DER encoded signature + sighash_type, requires an allocation. + fn push_ecdsa_signature(&mut self, signature: ecdsa::Signature) { + self.push(signature.serialize()) } - } - - /// Return the nth element in the witness, if any - pub fn nth(&self, index: usize) -> Option<&[u8]> { - let pos = decode_cursor(&self.content, self.indices_start, index)?; - self.element_at(pos) - } - - /// Get Tapscript following BIP341 rules regarding accounting for an annex. - /// - /// This does not guarantee that this represents a P2TR [`Witness`]. It - /// merely gets the second to last or third to last element depending on - /// the first byte of the last element being equal to 0x50. - /// - /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. - pub fn tapscript(&self) -> Option<&Script> { - self.last().and_then(|last| { - // From BIP341: - // If there are at least two witness elements, and the first byte of - // the last element is 0x50, this last element is called annex a - // and is removed from the witness stack. - if self.len() >= 3 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { - self.nth(self.len() - 3).map(Script::from_bytes) - } else if self.len() >= 2 { - self.nth(self.len() - 2).map(Script::from_bytes) - } else { - None - } - }) - } - - /// Get the taproot control block following BIP341 rules. - /// - /// This does not guarantee that this represents a P2TR [`Witness`]. It - /// merely gets the last or second to last element depending on the first - /// byte of the last element being equal to 0x50. - /// - /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. - pub fn taproot_control_block(&self) -> Option<&[u8]> { - self.last().and_then(|last| { - // From BIP341: - // If there are at least two witness elements, and the first byte of - // the last element is 0x50, this last element is called annex a - // and is removed from the witness stack. - if self.len() >= 3 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { - self.nth(self.len() - 2) - } else if self.len() >= 2 { - Some(last) - } else { - None - } - }) - } - - /// Get the taproot annex following BIP341 rules. - /// - /// This does not guarantee that this represents a P2TR [`Witness`]. - /// - /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. - pub fn taproot_annex(&self) -> Option<&[u8]> { - self.last().and_then(|last| { - // From BIP341: - // If there are at least two witness elements, and the first byte of - // the last element is 0x50, this last element is called annex a - // and is removed from the witness stack. - if self.len() >= 2 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { - Some(last) - } else { - None - } - }) - } - - /// Get the p2wsh witness script following BIP141 rules. - /// - /// This does not guarantee that this represents a P2WS [`Witness`]. - /// - /// See [`Script::is_p2wsh`] to check whether this is actually a P2WSH witness. - pub fn witness_script(&self) -> Option<&Script> { self.last().map(Script::from_bytes) } -} - -impl Index for Witness { - type Output = [u8]; - - fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("out of bounds") } -} - -impl<'a> Iterator for Iter<'a> { - type Item = &'a [u8]; - - fn next(&mut self) -> Option { - let index = decode_cursor(self.inner, self.indices_start, self.current_index)?; - let mut slice = &self.inner[index..]; // Start of element. - let element_len = compact_size::decode_unchecked(&mut slice); - // Compact size should always fit into a u32 because of `MAX_SIZE` in Core. - // ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264 - let end = element_len as usize; - self.current_index += 1; - Some(&slice[..end]) - } - - fn size_hint(&self) -> (usize, Option) { - let total_count = (self.inner.len() - self.indices_start) / 4; - let remaining = total_count - self.current_index; - (remaining, Some(remaining)) - } -} - -impl<'a> ExactSizeIterator for Iter<'a> {} - -impl<'a> IntoIterator for &'a Witness { - type IntoIter = Iter<'a>; - type Item = &'a [u8]; - - fn into_iter(self) -> Self::IntoIter { self.iter() } -} - -// Serde keep backward compatibility with old Vec> format -#[cfg(feature = "serde")] -impl serde::Serialize for Witness { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeSeq; - - let human_readable = serializer.is_human_readable(); - let mut seq = serializer.serialize_seq(Some(self.witness_elements))?; - - // Note that the `Iter` strips the varints out when iterating. - for elem in self.iter() { - if human_readable { - seq.serialize_element(&crate::serde_utils::SerializeBytesAsHex(elem))?; - } else { - seq.serialize_element(&elem)?; - } - } - seq.end() - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Witness { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use crate::prelude::String; - - struct Visitor; // Human-readable visitor. - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = Witness; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a sequence of hex arrays") - } - - fn visit_seq>( - self, - mut a: A, - ) -> Result { - use hex::FromHex; - use hex::HexToBytesError::*; - use serde::de::{self, Unexpected}; - - let mut ret = match a.size_hint() { - Some(len) => Vec::with_capacity(len), - None => Vec::new(), - }; - - while let Some(elem) = a.next_element::()? { - let vec = Vec::::from_hex(&elem).map_err(|e| match e { - InvalidChar(ref e) => match core::char::from_u32(e.invalid_char().into()) { - Some(c) => de::Error::invalid_value( - Unexpected::Char(c), - &"a valid hex character", - ), - None => de::Error::invalid_value( - Unexpected::Unsigned(e.invalid_char().into()), - &"a valid hex character", - ), - }, - OddLengthString(ref e) => - de::Error::invalid_length(e.length(), &"an even length string"), - })?; - ret.push(vec); + + /// Get Tapscript following BIP341 rules regarding accounting for an annex. + /// + /// This does not guarantee that this represents a P2TR [`Witness`]. It + /// merely gets the second to last or third to last element depending on + /// the first byte of the last element being equal to 0x50. + /// + /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. + fn tapscript(&self) -> Option<&Script> { + self.last().and_then(|last| { + // From BIP341: + // If there are at least two witness elements, and the first byte of + // the last element is 0x50, this last element is called annex a + // and is removed from the witness stack. + if self.len() >= 3 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { + self.nth(self.len() - 3).map(Script::from_bytes) + } else if self.len() >= 2 { + self.nth(self.len() - 2).map(Script::from_bytes) + } else { + None } - Ok(Witness::from_slice(&ret)) - } + }) } - if deserializer.is_human_readable() { - deserializer.deserialize_seq(Visitor) - } else { - let vec: Vec> = serde::Deserialize::deserialize(deserializer)?; - Ok(Witness::from_slice(&vec)) + /// Get the taproot control block following BIP341 rules. + /// + /// This does not guarantee that this represents a P2TR [`Witness`]. It + /// merely gets the last or second to last element depending on the first + /// byte of the last element being equal to 0x50. + /// + /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. + fn taproot_control_block(&self) -> Option<&[u8]> { + self.last().and_then(|last| { + // From BIP341: + // If there are at least two witness elements, and the first byte of + // the last element is 0x50, this last element is called annex a + // and is removed from the witness stack. + if self.len() >= 3 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { + self.nth(self.len() - 2) + } else if self.len() >= 2 { + Some(last) + } else { + None + } + }) } + + /// Get the taproot annex following BIP341 rules. + /// + /// This does not guarantee that this represents a P2TR [`Witness`]. + /// + /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness. + fn taproot_annex(&self) -> Option<&[u8]> { + self.last().and_then(|last| { + // From BIP341: + // If there are at least two witness elements, and the first byte of + // the last element is 0x50, this last element is called annex a + // and is removed from the witness stack. + if self.len() >= 2 && last.first() == Some(&TAPROOT_ANNEX_PREFIX) { + Some(last) + } else { + None + } + }) + } + + /// Get the p2wsh witness script following BIP141 rules. + /// + /// This does not guarantee that this represents a P2WS [`Witness`]. + /// + /// See [`Script::is_p2wsh`] to check whether this is actually a P2WSH witness. + fn witness_script(&self) -> Option<&Script> { self.last().map(Script::from_bytes) } + } } -impl From>> for Witness { - fn from(vec: Vec>) -> Self { Witness::from_slice(&vec) } -} - -impl From<&[&[u8]]> for Witness { - fn from(slice: &[&[u8]]) -> Self { Witness::from_slice(slice) } -} - -impl From<&[Vec]> for Witness { - fn from(slice: &[Vec]) -> Self { Witness::from_slice(slice) } -} - -impl From> for Witness { - fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) } -} - -impl Default for Witness { - fn default() -> Self { Self::new() } -} - -#[cfg(feature = "arbitrary")] -impl<'a> Arbitrary<'a> for Witness { - fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { - let arbitrary_bytes = Vec::>::arbitrary(u)?; - Ok(Witness::from_slice(&arbitrary_bytes)) - } +/// Correctness Requirements: value must always fit within u32 +// This is duplicated in `primitives::witness`, if you change it please do so over there also. +#[inline] +fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) { + let start = start_of_indices + index * 4; + let end = start + 4; + bytes[start..end] + .copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("larger than u32"))); } #[cfg(test)] @@ -649,120 +236,6 @@ mod test { use crate::sighash::EcdsaSighashType; use crate::Transaction; - // Appends all the indices onto the end of a list of elements. - fn append_u32_vec(elements: &[u8], indices: &[u32]) -> Vec { - let mut v = elements.to_vec(); - for &num in indices { - v.extend_from_slice(&num.to_ne_bytes()); - } - v - } - - // A witness with a single element that is empty (zero length). - fn single_empty_element() -> Witness { - // The first is 0 serialized as a compact size integer. - // The last four bytes represent start at index 0. - let content = [0_u8; 5]; - - Witness { witness_elements: 1, content: content.to_vec(), indices_start: 1 } - } - - #[test] - fn witness_debug_can_display_empty_element() { - let witness = single_empty_element(); - println!("{:?}", witness); - } - - #[test] - fn witness_single_empty_element() { - let mut got = Witness::new(); - got.push(&[]); - let want = single_empty_element(); - assert_eq!(got, want) - } - - #[test] - fn push() { - // Sanity check default. - let mut witness = Witness::default(); - assert_eq!(witness.last(), None); - assert_eq!(witness.second_to_last(), None); - - assert_eq!(witness.nth(0), None); - assert_eq!(witness.nth(1), None); - assert_eq!(witness.nth(2), None); - assert_eq!(witness.nth(3), None); - - // Push a single byte element onto the witness stack. - let push = [0_u8]; - witness.push(&push); - - let elements = [1u8, 0]; - let expected = Witness { - witness_elements: 1, - content: append_u32_vec(&elements, &[0]), // Start at index 0. - indices_start: elements.len(), - }; - assert_eq!(witness, expected); - - let element_0 = push.as_slice(); - assert_eq!(element_0, &witness[0]); - - assert_eq!(witness.second_to_last(), None); - assert_eq!(witness.last(), Some(element_0)); - - assert_eq!(witness.nth(0), Some(element_0)); - assert_eq!(witness.nth(1), None); - assert_eq!(witness.nth(2), None); - assert_eq!(witness.nth(3), None); - - // Now push 2 byte element onto the witness stack. - let push = [2u8, 3u8]; - witness.push(&push); - - let elements = [1u8, 0, 2, 2, 3]; - let expected = Witness { - witness_elements: 2, - content: append_u32_vec(&elements, &[0, 2]), - indices_start: elements.len(), - }; - assert_eq!(witness, expected); - - let element_1 = push.as_slice(); - assert_eq!(element_1, &witness[1]); - - assert_eq!(witness.nth(0), Some(element_0)); - assert_eq!(witness.nth(1), Some(element_1)); - assert_eq!(witness.nth(2), None); - assert_eq!(witness.nth(3), None); - - assert_eq!(witness.second_to_last(), Some(element_0)); - assert_eq!(witness.last(), Some(element_1)); - - // Now push another 2 byte element onto the witness stack. - let push = [4u8, 5u8]; - witness.push(&push); - - let elements = [1u8, 0, 2, 2, 3, 2, 4, 5]; - let expected = Witness { - witness_elements: 3, - content: append_u32_vec(&elements, &[0, 2, 5]), - indices_start: elements.len(), - }; - assert_eq!(witness, expected); - - let element_2 = push.as_slice(); - assert_eq!(element_2, &witness[2]); - - assert_eq!(witness.nth(0), Some(element_0)); - assert_eq!(witness.nth(1), Some(element_1)); - assert_eq!(witness.nth(2), Some(element_2)); - assert_eq!(witness.nth(3), None); - - assert_eq!(witness.second_to_last(), Some(element_1)); - assert_eq!(witness.last(), Some(element_2)); - } - #[test] fn exact_sized_iterator() { let mut witness = Witness::default(); @@ -931,62 +404,13 @@ mod test { let bytes = hex!("24000000ffffffffffffffffffffffff"); assert!(deserialize::(&bytes).is_err()); // OversizedVectorAllocation } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_backward_compatibility() { - let old_witness_format = vec![vec![0u8], vec![2]]; - let new_witness_format = Witness::from_slice(&old_witness_format); - - let old = bincode::serialize(&old_witness_format).unwrap(); - let new = bincode::serialize(&new_witness_format).unwrap(); - - assert_eq!(old, new); - } - - #[cfg(feature = "serde")] - fn arbitrary_witness() -> Witness { - let mut witness = Witness::default(); - - witness.push(&[0_u8]); - witness.push(&[1_u8; 32]); - witness.push(&[2_u8; 72]); - - witness - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_roundtrips() { - let original = arbitrary_witness(); - let ser = bincode::serialize(&original).unwrap(); - let rinsed: Witness = bincode::deserialize(&ser).unwrap(); - assert_eq!(rinsed, original); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_human_roundtrips() { - let original = arbitrary_witness(); - let ser = serde_json::to_string(&original).unwrap(); - let rinsed: Witness = serde_json::from_str(&ser).unwrap(); - assert_eq!(rinsed, original); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_human() { - let witness = Witness::from_slice(&[vec![0u8, 123, 75], vec![2u8, 6, 3, 7, 8]]); - let json = serde_json::to_string(&witness).unwrap(); - assert_eq!(json, r#"["007b4b","0206030708"]"#); - } } #[cfg(bench)] mod benches { use test::{black_box, Bencher}; - use super::Witness; + use super::{Witness, WitnessExt}; #[bench] pub fn bench_big_witness_to_vec(bh: &mut Bencher) { diff --git a/internals/Cargo.toml b/internals/Cargo.toml index 07bbbdca2..feb14cde0 100644 --- a/internals/Cargo.toml +++ b/internals/Cargo.toml @@ -15,12 +15,13 @@ exclude = ["tests", "contrib"] [features] default = [] -std = ["alloc"] -alloc = [] +std = ["alloc", "hex/std"] +alloc = ["hex/alloc"] test-serde = ["serde", "serde_json", "bincode"] [dependencies] +hex = { package = "hex-conservative", version = "0.2.0", default-features = false } serde = { version = "1.0.103", default-features = false, optional = true } # Don't enable these directly, use `test-serde` feature instead. diff --git a/internals/src/serde.rs b/internals/src/serde.rs index e2366d367..d75570e85 100644 --- a/internals/src/serde.rs +++ b/internals/src/serde.rs @@ -309,3 +309,17 @@ macro_rules! serde_round_trip ( assert_eq!($var, decoded); }) ); + +/// Serializes a byte slice using the `hex` crate. +pub struct SerializeBytesAsHex<'a>(pub &'a [u8]); + +impl<'a> serde::Serialize for SerializeBytesAsHex<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use hex::DisplayHex; + + serializer.collect_str(&format_args!("{:x}", self.0.as_hex())) + } +} diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 607b29376..4bc7d92c4 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -18,7 +18,7 @@ exclude = ["tests", "contrib"] default = ["std"] std = ["alloc", "hashes/std", "hex/std", "internals/std", "io/std", "units/std"] alloc = ["hashes/alloc", "hex/alloc", "internals/alloc", "io/alloc", "units/alloc"] -serde = ["dep:serde", "hashes/serde", "hex/serde", "internals/serde", "units/serde", "alloc"] +serde = ["dep:serde", "hashes/serde", "internals/serde", "units/serde", "alloc"] arbitrary = ["dep:arbitrary", "units/arbitrary"] [dependencies] @@ -33,6 +33,8 @@ ordered = { version = "0.2.0", optional = true } serde = { version = "1.0.103", default-features = false, features = ["derive", "alloc"], optional = true } [dev-dependencies] +serde_json = "1.0.0" +bincode = "1.3.1" [target.'cfg(mutate)'.dev-dependencies] mutagen = { git = "https://github.com/llogiq/mutagen" } diff --git a/primitives/README.md b/primitives/README.md index 0b93090b1..6eaae8868 100644 --- a/primitives/README.md +++ b/primitives/README.md @@ -3,6 +3,11 @@ This crate provides primitive data types that are used throughout the [`rust-bitcoin`](https://github.com/rust-bitcoin) ecosystem. +## Semver compliance + +Functions marked as unstable (e.g. `foo__unstable`) are not guaranteed to uphold semver compliance. +They are primarily provided to support `rust-bitcoin`. + ## Minimum Supported Rust Version (MSRV) This library should always compile with any combination of features on **Rust 1.63.0**. diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 4ba3ef7ff..2cef130e6 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -40,13 +40,18 @@ pub mod pow; pub mod script; pub mod sequence; pub mod transaction; +#[cfg(feature = "alloc")] +pub mod witness; #[doc(inline)] pub use units::*; #[doc(inline)] #[cfg(feature = "alloc")] -pub use self::locktime::{absolute, relative}; +pub use self::{ + locktime::{absolute, relative}, + witness::Witness, +}; #[doc(inline)] pub use self::{ block::{BlockHash, WitnessCommitment}, diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs new file mode 100644 index 000000000..30c119be5 --- /dev/null +++ b/primitives/src/witness.rs @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! A witness. +//! +//! This module contains the [`Witness`] struct and related methods to operate on it + +use core::fmt; +use core::ops::Index; + +#[cfg(feature = "arbitrary")] +use arbitrary::{Arbitrary, Unstructured}; +use internals::compact_size; + +use crate::prelude::Vec; + +/// The Witness is the data used to unlock bitcoin since the [segwit upgrade]. +/// +/// Can be logically seen as an array of bytestrings, i.e. `Vec>`, and it is serialized on the wire +/// in that format. You can convert between this type and `Vec>` by using [`Witness::from_slice`] +/// and [`Witness::to_bytes`]. +/// +/// For serialization and deserialization performance it is stored internally as a single `Vec`, +/// saving some allocations. +/// +/// [segwit upgrade]: +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Witness { + /// Contains the witness `Vec>` serialization. + /// + /// Does not include the initial varint indicating the number of elements. Each element however, + /// does include a varint indicating the element length. The number of elements is stored in + /// `witness_elements`. + /// + /// Concatenated onto the end of `content` is the index area. This is a `4 * witness_elements` + /// bytes area which stores the index of the start of each witness item. + content: Vec, + + /// The number of elements in the witness. + /// + /// Stored separately (instead of as a compact size encoding in the initial part of content) so + /// that methods like [`Witness::push`] don't have to shift the entire array. + witness_elements: usize, + + /// This is the valid index pointing to the beginning of the index area. + /// + /// Said another way, this is the total length of all witness elements serialized (without the + /// element count but with their sizes serialized as compact size). + indices_start: usize, +} + +impl Witness { + /// Creates a new empty [`Witness`]. + #[inline] + pub const fn new() -> Self { + Witness { content: Vec::new(), witness_elements: 0, indices_start: 0 } + } + + /// Creates a new [`Witness`] from inner parts. + /// + /// This function leaks implementation details of the `Witness`, as such it is unstable and + /// should not be relied upon (it is primarily provided for use in `rust-bitcoin`). + /// + /// UNSTABLE: This function may change, break, or disappear in any release. + #[inline] + #[doc(hidden)] + #[allow(non_snake_case)] // Because of `__unstable`. + pub fn from_parts__unstable(content: Vec, witness_elements: usize, indices_start: usize) -> Self { + Witness { content, witness_elements, indices_start } + } + + /// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item. + pub fn from_slice>(slice: &[T]) -> Self { + let witness_elements = slice.len(); + let index_size = witness_elements * 4; + let content_size = slice + .iter() + .map(|elem| elem.as_ref().len() + compact_size::encoded_size(elem.as_ref().len())) + .sum(); + + let mut content = alloc::vec![0u8; content_size + index_size]; + let mut cursor = 0usize; + for (i, elem) in slice.iter().enumerate() { + encode_cursor(&mut content, content_size, i, cursor); + let encoded = compact_size::encode(elem.as_ref().len()); + let encoded_size = encoded.as_slice().len(); + content[cursor..cursor + encoded_size].copy_from_slice(encoded.as_slice()); + cursor += encoded_size; + content[cursor..cursor + elem.as_ref().len()].copy_from_slice(elem.as_ref()); + cursor += elem.as_ref().len(); + } + + Witness { witness_elements, content, indices_start: content_size } + } + + /// Convenience method to create an array of byte-arrays from this witness. + pub fn to_bytes(&self) -> Vec> { self.iter().map(|s| s.to_vec()).collect() } + + /// Returns `true` if the witness contains no element. + pub fn is_empty(&self) -> bool { self.witness_elements == 0 } + + /// Returns a struct implementing [`Iterator`]. + pub fn iter(&self) -> Iter { + Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 } + } + + /// Returns the number of elements this witness holds. + pub fn len(&self) -> usize { self.witness_elements } + + /// Returns the number of bytes this witness contributes to a transactions total size. + pub fn size(&self) -> usize { + let mut size: usize = 0; + + size += compact_size::encoded_size(self.witness_elements); + size += self + .iter() + .map(|witness_element| { + let len = witness_element.len(); + compact_size::encoded_size(len) + len + }) + .sum::(); + + size + } + + /// Clear the witness. + pub fn clear(&mut self) { + self.content.clear(); + self.witness_elements = 0; + self.indices_start = 0; + } + + /// Push a new element on the witness, requires an allocation. + pub fn push>(&mut self, new_element: T) { + self.push_slice(new_element.as_ref()); + } + + /// Push a new element slice onto the witness stack. + fn push_slice(&mut self, new_element: &[u8]) { + self.witness_elements += 1; + let previous_content_end = self.indices_start; + let encoded = compact_size::encode(new_element.len()); + let encoded_size = encoded.as_slice().len(); + let current_content_len = self.content.len(); + let new_item_total_len = encoded_size + new_element.len(); + self.content.resize(current_content_len + new_item_total_len + 4, 0); + + self.content[previous_content_end..].rotate_right(new_item_total_len); + self.indices_start += new_item_total_len; + encode_cursor( + &mut self.content, + self.indices_start, + self.witness_elements - 1, + previous_content_end, + ); + + let end_compact_size = previous_content_end + encoded_size; + self.content[previous_content_end..end_compact_size].copy_from_slice(encoded.as_slice()); + self.content[end_compact_size..end_compact_size + new_element.len()] + .copy_from_slice(new_element); + } + + /// Note `index` is the index into the `content` vector and should be the result of calling + /// `decode_cursor`, which returns a valid index. + fn element_at(&self, index: usize) -> Option<&[u8]> { + let mut slice = &self.content[index..]; // Start of element. + let element_len = compact_size::decode_unchecked(&mut slice); + // Compact size should always fit into a u32 because of `MAX_SIZE` in Core. + // ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264 + let end = element_len as usize; + Some(&slice[..end]) + } + + /// Returns the last element in the witness, if any. + pub fn last(&self) -> Option<&[u8]> { + if self.witness_elements == 0 { + None + } else { + self.nth(self.witness_elements - 1) + } + } + + /// Returns the second-to-last element in the witness, if any. + pub fn second_to_last(&self) -> Option<&[u8]> { + if self.witness_elements <= 1 { + None + } else { + self.nth(self.witness_elements - 2) + } + } + + /// Return the nth element in the witness, if any + pub fn nth(&self, index: usize) -> Option<&[u8]> { + let pos = decode_cursor(&self.content, self.indices_start, index)?; + self.element_at(pos) + } +} + +/// Correctness Requirements: value must always fit within u32 +// This is duplicated in `bitcoin::blockdata::witness`, if you change it please do so over there also. +#[inline] +fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) { + let start = start_of_indices + index * 4; + let end = start + 4; + bytes[start..end] + .copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("larger than u32"))); +} + +// This is duplicated in `bitcoin::blockdata::witness`, if you change them do so over there also. +#[inline] +fn decode_cursor(bytes: &[u8], start_of_indices: usize, index: usize) -> Option { + let start = start_of_indices + index * 4; + let end = start + 4; + if end > bytes.len() { + None + } else { + Some(u32::from_ne_bytes(bytes[start..end].try_into().expect("is u32 size")) as usize) + } +} + +impl fmt::Debug for Witness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + if f.alternate() { + fmt_debug_pretty(self, f) + } else { + fmt_debug(self, f) + } + } +} + +fn fmt_debug(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + #[rustfmt::skip] + let comma_or_close = |current_index, last_index| { + if current_index == last_index { "]" } else { ", " } + }; + + f.write_str("Witness: { ")?; + write!(f, "indices: {}, ", w.witness_elements)?; + write!(f, "indices_start: {}, ", w.indices_start)?; + f.write_str("witnesses: [")?; + + let instructions = w.iter(); + match instructions.len().checked_sub(1) { + Some(last_instruction) => { + for (i, instruction) in instructions.enumerate() { + let bytes = instruction.iter(); + match bytes.len().checked_sub(1) { + Some(last_byte) => { + f.write_str("[")?; + for (j, byte) in bytes.enumerate() { + write!(f, "{:#04x}", byte)?; + f.write_str(comma_or_close(j, last_byte))?; + } + } + None => { + // This is possible because the varint is not part of the instruction (see Iter). + write!(f, "[]")?; + } + } + f.write_str(comma_or_close(i, last_instruction))?; + } + } + None => { + // Witnesses can be empty because the 0x00 var int is not stored in content. + write!(f, "]")?; + } + } + + f.write_str(" }") +} + +fn fmt_debug_pretty(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Witness: {\n")?; + writeln!(f, " indices: {},", w.witness_elements)?; + writeln!(f, " indices_start: {},", w.indices_start)?; + f.write_str(" witnesses: [\n")?; + + for instruction in w.iter() { + f.write_str(" [")?; + for (j, byte) in instruction.iter().enumerate() { + if j > 0 { + f.write_str(", ")?; + } + write!(f, "{:#04x}", byte)?; + } + f.write_str("],\n")?; + } + + writeln!(f, " ],")?; + writeln!(f, "}}") +} + +/// An iterator returning individual witness elements. +pub struct Iter<'a> { + inner: &'a [u8], + indices_start: usize, + current_index: usize, +} + +impl Index for Witness { + type Output = [u8]; + + fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("out of bounds") } +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + let index = decode_cursor(self.inner, self.indices_start, self.current_index)?; + let mut slice = &self.inner[index..]; // Start of element. + let element_len = compact_size::decode_unchecked(&mut slice); + // Compact size should always fit into a u32 because of `MAX_SIZE` in Core. + // ref: https://github.com/rust-bitcoin/rust-bitcoin/issues/3264 + let end = element_len as usize; + self.current_index += 1; + Some(&slice[..end]) + } + + fn size_hint(&self) -> (usize, Option) { + let total_count = (self.inner.len() - self.indices_start) / 4; + let remaining = total_count - self.current_index; + (remaining, Some(remaining)) + } +} + +impl<'a> ExactSizeIterator for Iter<'a> {} + +impl<'a> IntoIterator for &'a Witness { + type IntoIter = Iter<'a>; + type Item = &'a [u8]; + + fn into_iter(self) -> Self::IntoIter { self.iter() } +} + +// Serde keep backward compatibility with old Vec> format +#[cfg(feature = "serde")] +impl serde::Serialize for Witness { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeSeq; + + let human_readable = serializer.is_human_readable(); + let mut seq = serializer.serialize_seq(Some(self.witness_elements))?; + + // Note that the `Iter` strips the varints out when iterating. + for elem in self.iter() { + if human_readable { + seq.serialize_element(&internals::serde::SerializeBytesAsHex(elem))?; + } else { + seq.serialize_element(&elem)?; + } + } + seq.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Witness { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use crate::prelude::String; + + struct Visitor; // Human-readable visitor. + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Witness; + + fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "a sequence of hex arrays") + } + + fn visit_seq>( + self, + mut a: A, + ) -> Result { + use hex::FromHex; + use hex::HexToBytesError::*; + use serde::de::{self, Unexpected}; + + let mut ret = match a.size_hint() { + Some(len) => Vec::with_capacity(len), + None => Vec::new(), + }; + + while let Some(elem) = a.next_element::()? { + let vec = Vec::::from_hex(&elem).map_err(|e| match e { + InvalidChar(ref e) => match core::char::from_u32(e.invalid_char().into()) { + Some(c) => de::Error::invalid_value( + Unexpected::Char(c), + &"a valid hex character", + ), + None => de::Error::invalid_value( + Unexpected::Unsigned(e.invalid_char().into()), + &"a valid hex character", + ), + }, + OddLengthString(ref e) => + de::Error::invalid_length(e.length(), &"an even length string"), + })?; + ret.push(vec); + } + Ok(Witness::from_slice(&ret)) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_seq(Visitor) + } else { + let vec: Vec> = serde::Deserialize::deserialize(deserializer)?; + Ok(Witness::from_slice(&vec)) + } + } +} + +impl From>> for Witness { + fn from(vec: Vec>) -> Self { Witness::from_slice(&vec) } +} + +impl From<&[&[u8]]> for Witness { + fn from(slice: &[&[u8]]) -> Self { Witness::from_slice(slice) } +} + +impl From<&[Vec]> for Witness { + fn from(slice: &[Vec]) -> Self { Witness::from_slice(slice) } +} + +impl From> for Witness { + fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) } +} + +impl Default for Witness { + fn default() -> Self { Self::new() } +} + +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for Witness { + fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { + let arbitrary_bytes = Vec::>::arbitrary(u)?; + Ok(Witness::from_slice(&arbitrary_bytes)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + // Appends all the indices onto the end of a list of elements. + fn append_u32_vec(elements: &[u8], indices: &[u32]) -> Vec { + let mut v = elements.to_vec(); + for &num in indices { + v.extend_from_slice(&num.to_ne_bytes()); + } + v + } + + // A witness with a single element that is empty (zero length). + fn single_empty_element() -> Witness { + // The first is 0 serialized as a compact size integer. + // The last four bytes represent start at index 0. + let content = [0_u8; 5]; + + Witness { + witness_elements: 1, + content: content.to_vec(), + indices_start: 1, + } + } + + #[test] + fn witness_debug_can_display_empty_element() { + let witness = single_empty_element(); + println!("{:?}", witness); + } + + #[test] + fn witness_single_empty_element() { + let mut got = Witness::new(); + got.push(&[]); + let want = single_empty_element(); + assert_eq!(got, want) + } + + #[test] + fn push() { + // Sanity check default. + let mut witness = Witness::default(); + assert_eq!(witness.last(), None); + assert_eq!(witness.second_to_last(), None); + + assert_eq!(witness.nth(0), None); + assert_eq!(witness.nth(1), None); + assert_eq!(witness.nth(2), None); + assert_eq!(witness.nth(3), None); + + // Push a single byte element onto the witness stack. + let push = [0_u8]; + witness.push(&push); + + let elements = [1u8, 0]; + let expected = Witness { + witness_elements: 1, + content: append_u32_vec(&elements, &[0]), // Start at index 0. + indices_start: elements.len(), + }; + assert_eq!(witness, expected); + + let element_0 = push.as_slice(); + assert_eq!(element_0, &witness[0]); + + assert_eq!(witness.second_to_last(), None); + assert_eq!(witness.last(), Some(element_0)); + + assert_eq!(witness.nth(0), Some(element_0)); + assert_eq!(witness.nth(1), None); + assert_eq!(witness.nth(2), None); + assert_eq!(witness.nth(3), None); + + // Now push 2 byte element onto the witness stack. + let push = [2u8, 3u8]; + witness.push(&push); + + let elements = [1u8, 0, 2, 2, 3]; + let expected = Witness { + witness_elements: 2, + content: append_u32_vec(&elements, &[0, 2]), + indices_start: elements.len(), + }; + assert_eq!(witness, expected); + + let element_1 = push.as_slice(); + assert_eq!(element_1, &witness[1]); + + assert_eq!(witness.nth(0), Some(element_0)); + assert_eq!(witness.nth(1), Some(element_1)); + assert_eq!(witness.nth(2), None); + assert_eq!(witness.nth(3), None); + + assert_eq!(witness.second_to_last(), Some(element_0)); + assert_eq!(witness.last(), Some(element_1)); + + // Now push another 2 byte element onto the witness stack. + let push = [4u8, 5u8]; + witness.push(&push); + + let elements = [1u8, 0, 2, 2, 3, 2, 4, 5]; + let expected = Witness { + witness_elements: 3, + content: append_u32_vec(&elements, &[0, 2, 5]), + indices_start: elements.len(), + }; + assert_eq!(witness, expected); + + let element_2 = push.as_slice(); + assert_eq!(element_2, &witness[2]); + + assert_eq!(witness.nth(0), Some(element_0)); + assert_eq!(witness.nth(1), Some(element_1)); + assert_eq!(witness.nth(2), Some(element_2)); + assert_eq!(witness.nth(3), None); + + assert_eq!(witness.second_to_last(), Some(element_1)); + assert_eq!(witness.last(), Some(element_2)); + } + + #[test] + fn exact_sized_iterator() { + let arbitrary_element = [1_u8, 2, 3]; + let num_pushes = 5; // Somewhat arbitrary. + + let mut witness = Witness::default(); + + for i in 0..num_pushes { + assert_eq!(witness.iter().len(), i); + witness.push(&arbitrary_element); + } + + let mut iter = witness.iter(); + for i in (0..=num_pushes).rev() { + assert_eq!(iter.len(), i); + iter.next(); + } + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_backward_compatibility() { + let old_witness_format = vec![vec![0u8], vec![2]]; + let new_witness_format = Witness::from_slice(&old_witness_format); + + let old = bincode::serialize(&old_witness_format).unwrap(); + let new = bincode::serialize(&new_witness_format).unwrap(); + + assert_eq!(old, new); + } + + #[cfg(feature = "serde")] + fn arbitrary_witness() -> Witness { + let mut witness = Witness::default(); + + witness.push(&[0_u8]); + witness.push(&[1_u8; 32]); + witness.push(&[2_u8; 72]); + + witness + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_roundtrips() { + let original = arbitrary_witness(); + let ser = bincode::serialize(&original).unwrap(); + let rinsed: Witness = bincode::deserialize(&ser).unwrap(); + assert_eq!(rinsed, original); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_human_roundtrips() { + let original = arbitrary_witness(); + let ser = serde_json::to_string(&original).unwrap(); + let rinsed: Witness = serde_json::from_str(&ser).unwrap(); + assert_eq!(rinsed, original); + + } + + #[test] + #[cfg(feature = "serde")] + fn serde_human() { + let witness = Witness::from_slice(&[vec![0u8, 123, 75], vec![2u8, 6, 3, 7, 8]]); + let json = serde_json::to_string(&witness).unwrap(); + assert_eq!(json, r#"["007b4b","0206030708"]"#); + } +}