diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index e69e201cb..73f21f467 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]] @@ -204,7 +207,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 541d54af8..0cc3f3b5d 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]] @@ -206,7 +209,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" dependencies = [ "arrayvec", - "serde", ] [[package]] diff --git a/README.md b/README.md index 970192a1a..a841d5122 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,13 @@ are no plans to do so. Of course, patches to fix specific consensus incompatibil 16-bit pointer sizes are not supported and we can't promise they will be. If you care about them please let us know, so we can know how large the interest is and possibly decide to support them. +### Semver compliance + +We try hard to maintain strict semver compliance with our releases. This codebase includes some +public functions marked unstable (e.g., `pub fn foo__unstable()`). These functions do not adhere to +semver rules; use them at your own discretion. + + ## Documentation Currently can be found on [docs.rs/bitcoin](https://docs.rs/bitcoin/). Patches to add usage examples 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 07cac752e..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 { @@ -193,31 +78,12 @@ impl Decodable for Witness { content.truncate(cursor); // Index space is now at the end of the Vec content.rotate_left(witness_index_space); - Ok(Witness { content, witness_elements, indices_start: cursor - witness_index_space }) + let indices_start = cursor - witness_index_space; + Ok(Witness::from_parts__unstable(content, witness_elements, indices_start)) } } } -/// 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); @@ -241,388 +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 } - } - - /// 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(); +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 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)?; - } + + /// 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 + } + }) } - 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 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 } - 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 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 + } + }) } - } -} -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) } -} + /// 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<&[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)] @@ -635,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(); @@ -917,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"]"#); + } +}