diff --git a/bitcoin/src/address/error.rs b/bitcoin/src/address/error.rs index c17471099..f1479425c 100644 --- a/bitcoin/src/address/error.rs +++ b/bitcoin/src/address/error.rs @@ -158,7 +158,7 @@ pub struct NetworkValidationError { impl fmt::Display for NetworkValidationError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "address ")?; - fmt::Display::fmt(&self.address.0, f)?; + fmt::Display::fmt(&self.address.inner(), f)?; write!(f, " is not valid on {}", self.required) } } diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 93bc290d8..df8e04067 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -308,103 +308,108 @@ pub enum AddressData { }, } -/// A Bitcoin address. -/// -/// ### Parsing addresses -/// -/// When parsing string as an address, one has to pay attention to the network, on which the parsed -/// address is supposed to be valid. For the purpose of this validation, `Address` has -/// [`is_valid_for_network`](Address::is_valid_for_network) method. In order to provide more safety, -/// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed -/// address has been checked. This marker type will prevent from calling certain functions unless the network -/// verification has been successfully completed. -/// -/// The result of parsing an address is `Address` suggesting that network of the parsed address -/// has not yet been verified. To perform this verification, method [`require_network`](Address::require_network) -/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds, -/// `Address` is returned. -/// -/// The types `Address` and `Address` are synonymous, i. e. they can be used interchangeably. -/// -/// ```rust -/// use std::str::FromStr; -/// use bitcoin::{Address, Network}; -/// use bitcoin::address::{NetworkUnchecked, NetworkChecked}; -/// -/// // variant 1 -/// let address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap(); -/// let _address: Address = address.require_network(Network::Bitcoin).unwrap(); -/// -/// // variant 2 -/// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap() -/// .require_network(Network::Bitcoin).unwrap(); -/// -/// // variant 3 -/// let _address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::>() -/// .unwrap().require_network(Network::Bitcoin).unwrap(); -/// ``` -/// -/// ### Formatting addresses -/// -/// To format address into its textual representation, both `Debug` (for usage in programmer-facing, -/// debugging context) and `Display` (for user-facing output) can be used, with the following caveats: -/// -/// 1. `Display` is implemented only for `Address`: -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap().assume_checked(); -/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); -/// ``` -/// -/// ```ignore -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap(); -/// let s = address.to_string(); // does not compile -/// ``` -/// -/// 2. `Debug` on `Address` does not produce clean address but address wrapped by -/// an indicator that its network has not been checked. This is to encourage programmer to properly -/// check the network and use `Display` in user-facing context. -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkUnchecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap(); -/// assert_eq!(format!("{:?}", address), "Address(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)"); -/// ``` -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap().assume_checked(); -/// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); -/// ``` -/// -/// ### Relevant BIPs -/// -/// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki) -/// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) -/// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) -/// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki) -/// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) -/// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -// The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It -// is an implementation detail and users should not rely on it in their code. -#[repr(transparent)] -pub struct Address(AddressInner, PhantomData) -where - V: NetworkValidation; +internals::transparent_newtype! { + /// A Bitcoin address. + /// + /// ### Parsing addresses + /// + /// When parsing string as an address, one has to pay attention to the network, on which the parsed + /// address is supposed to be valid. For the purpose of this validation, `Address` has + /// [`is_valid_for_network`](Address::is_valid_for_network) method. In order to provide more safety, + /// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed + /// address has been checked. This marker type will prevent from calling certain functions unless the network + /// verification has been successfully completed. + /// + /// The result of parsing an address is `Address` suggesting that network of the parsed address + /// has not yet been verified. To perform this verification, method [`require_network`](Address::require_network) + /// can be called, providing network on which the address is supposed to be valid. If the verification succeeds, + /// `Address` is returned. + /// + /// The types `Address` and `Address` are synonymous, i. e. they can be used interchangeably. + /// + /// ```rust + /// use std::str::FromStr; + /// use bitcoin::{Address, Network}; + /// use bitcoin::address::{NetworkUnchecked, NetworkChecked}; + /// + /// // variant 1 + /// let address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap(); + /// let _address: Address = address.require_network(Network::Bitcoin).unwrap(); + /// + /// // variant 2 + /// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap() + /// .require_network(Network::Bitcoin).unwrap(); + /// + /// // variant 3 + /// let _address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::>() + /// .unwrap().require_network(Network::Bitcoin).unwrap(); + /// ``` + /// + /// ### Formatting addresses + /// + /// To format address into its textual representation, both `Debug` (for usage in programmer-facing, + /// debugging context) and `Display` (for user-facing output) can be used, with the following caveats: + /// + /// 1. `Display` is implemented only for `Address`: + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap().assume_checked(); + /// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); + /// ``` + /// + /// ```ignore + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap(); + /// let s = address.to_string(); // does not compile + /// ``` + /// + /// 2. `Debug` on `Address` does not produce clean address but address wrapped by + /// an indicator that its network has not been checked. This is to encourage programmer to properly + /// check the network and use `Display` in user-facing context. + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkUnchecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap(); + /// assert_eq!(format!("{:?}", address), "Address(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)"); + /// ``` + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap().assume_checked(); + /// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); + /// ``` + /// + /// ### Relevant BIPs + /// + /// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki) + /// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) + /// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) + /// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki) + /// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) + /// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + // The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It + // is an implementation detail and users should not rely on it in their code. + pub struct Address(PhantomData, AddressInner) + where + V: NetworkValidation; + + impl Address { + fn from_inner_ref(inner: &_) -> &Self; + } +} #[cfg(feature = "serde")] struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address); #[cfg(feature = "serde")] impl fmt::Display for DisplayUnchecked<'_, N> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0 .0, fmt) } + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0.inner(), fmt) } } #[cfg(feature = "serde")] @@ -433,7 +438,7 @@ impl<'de, U: NetworkValidationUnchecked> serde::Deserialize<'de> for Address { // We know that `U` is only ever `NetworkUnchecked` but the compiler does not. let address = v.parse::>().map_err(E::custom)?; - Ok(Address(address.0, PhantomData::)) + Ok(Address::from_inner(address.into_inner())) } } @@ -454,18 +459,30 @@ impl serde::Serialize for Address { /// Methods on [`Address`] that can be called on both `Address` and /// `Address`. impl Address { + fn from_inner(inner: AddressInner) -> Self { + Address(PhantomData, inner) + } + + fn into_inner(self) -> AddressInner { + self.1 + } + + fn inner(&self) -> &AddressInner { + &self.1 + } + /// Returns a reference to the address as if it was unchecked. pub fn as_unchecked(&self) -> &Address { - unsafe { &*(self as *const Address as *const Address) } + Address::from_inner_ref(self.inner()) } /// Marks the network of this address as unchecked. - pub fn into_unchecked(self) -> Address { Address(self.0, PhantomData) } + pub fn into_unchecked(self) -> Address { Address::from_inner(self.into_inner()) } /// Returns the [`NetworkKind`] of this address. pub fn network_kind(&self) -> NetworkKind { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { hash: _, ref network } => *network, P2sh { hash: _, ref network } => *network, Segwit { program: _, ref hrp } => NetworkKind::from(*hrp), @@ -481,7 +498,7 @@ impl Address { #[inline] pub fn p2pkh(pk: impl Into, network: impl Into) -> Address { let hash = pk.into(); - Self(AddressInner::P2pkh { hash, network: network.into() }, PhantomData) + Self::from_inner(AddressInner::P2pkh { hash, network: network.into() }) } /// Constructs a new pay-to-script-hash (P2SH) [`Address`] from a script. @@ -504,7 +521,7 @@ impl Address { /// The `hash` pre-image (redeem script) must not exceed 520 bytes in length /// otherwise outputs created from the returned address will be un-spendable. pub fn p2sh_from_hash(hash: ScriptHash, network: impl Into) -> Address { - Self(AddressInner::P2sh { hash, network: network.into() }, PhantomData) + Self::from_inner(AddressInner::P2sh { hash, network: network.into() }) } /// Constructs a new pay-to-witness-public-key-hash (P2WPKH) [`Address`] from a public key. @@ -577,7 +594,7 @@ impl Address { /// then you likely do not need this constructor. pub fn from_witness_program(program: WitnessProgram, hrp: impl Into) -> Address { let inner = AddressInner::Segwit { program, hrp: hrp.into() }; - Address(inner, PhantomData) + Address::from_inner(inner) } /// Gets the address type of the [`Address`]. @@ -587,7 +604,7 @@ impl Address { /// None if unknown, non-standard or related to the future witness version. #[inline] pub fn address_type(&self) -> Option { - match self.0 { + match *self.inner() { AddressInner::P2pkh { .. } => Some(AddressType::P2pkh), AddressInner::P2sh { .. } => Some(AddressType::P2sh), AddressInner::Segwit { ref program, hrp: _ } => @@ -609,7 +626,7 @@ impl Address { pub fn to_address_data(&self) -> AddressData { use AddressData::*; - match self.0 { + match *self.inner() { AddressInner::P2pkh { hash, network: _ } => P2pkh { pubkey_hash: hash }, AddressInner::P2sh { hash, network: _ } => P2sh { script_hash: hash }, AddressInner::Segwit { program, hrp: _ } => Segwit { witness_program: program }, @@ -620,7 +637,7 @@ impl Address { pub fn pubkey_hash(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { ref hash, network: _ } => Some(*hash), _ => None, } @@ -630,7 +647,7 @@ impl Address { pub fn script_hash(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { P2sh { ref hash, network: _ } => Some(*hash), _ => None, } @@ -640,7 +657,7 @@ impl Address { pub fn witness_program(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { Segwit { ref program, hrp: _ } => Some(*program), _ => None, } @@ -689,7 +706,7 @@ impl Address { /// Generates a script pubkey spending to this address. pub fn script_pubkey(&self) -> ScriptBuf { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { hash, network: _ } => ScriptBuf::new_p2pkh(hash), P2sh { hash, network: _ } => ScriptBuf::new_p2sh(hash), Segwit { ref program, hrp: _ } => { @@ -756,7 +773,7 @@ impl Address { /// This function doesn't make any allocations. pub fn matches_script_pubkey(&self, script: &Script) -> bool { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { ref hash, network: _ } if script.is_p2pkh() => &script.as_bytes()[3..23] == >::as_ref(hash), P2sh { ref hash, network: _ } if script.is_p2sh() => @@ -777,7 +794,7 @@ impl Address { /// - For SegWit addresses, the payload is the witness program. fn payload_as_bytes(&self) -> &[u8] { use AddressInner::*; - match self.0 { + match *self.inner() { P2sh { ref hash, network: _ } => hash.as_ref(), P2pkh { ref hash, network: _ } => hash.as_ref(), Segwit { ref program, hrp: _ } => program.program().as_bytes(), @@ -791,7 +808,7 @@ impl Address { /// /// This function is dangerous in case the address is not a valid checked address. pub fn assume_checked_ref(&self) -> &Address { - unsafe { &*(self as *const Address as *const Address) } + Address::from_inner_ref(self.inner()) } /// Parsed addresses do not always have *one* network. The problem is that legacy testnet, @@ -817,7 +834,7 @@ impl Address { /// ``` pub fn is_valid_for_network(&self, n: Network) -> bool { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { hash: _, ref network } => *network == NetworkKind::from(n), P2sh { hash: _, ref network } => *network == NetworkKind::from(n), Segwit { program: _, ref hrp } => *hrp == KnownHrp::from_network(n), @@ -882,7 +899,7 @@ impl Address { /// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses) /// on [`Address`]. #[inline] - pub fn assume_checked(self) -> Address { Address(self.0, PhantomData) } + pub fn assume_checked(self) -> Address { Address::from_inner(self.into_inner()) } /// Parse a bech32 Address string pub fn from_bech32_str(s: &str) -> Result, Bech32Error> { @@ -894,7 +911,7 @@ impl Address { let hrp = KnownHrp::from_hrp(hrp)?; let inner = AddressInner::Segwit { program, hrp }; - Ok(Address(inner, PhantomData)) + Ok(Address::from_inner(inner)) } /// Parse a base58 Address string @@ -927,7 +944,7 @@ impl Address { invalid => return Err(InvalidLegacyPrefixError { invalid }.into()), }; - Ok(Address(inner, PhantomData)) + Ok(Address::from_inner(inner)) } } @@ -938,16 +955,16 @@ impl From
for ScriptBuf { // Alternate formatting `{:#}` is used to return uppercase version of bech32 addresses which should // be used in QR codes, see [`Address::to_qr_uri`]. impl fmt::Display for Address { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, fmt) } + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.inner(), fmt) } } impl fmt::Debug for Address { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if V::IS_CHECKED { - fmt::Display::fmt(&self.0, f) + fmt::Display::fmt(&self.inner(), f) } else { write!(f, "Address(")?; - fmt::Display::fmt(&self.0, f)?; + fmt::Display::fmt(&self.inner(), f)?; write!(f, ")") } } @@ -975,10 +992,10 @@ impl FromStr for Address { if ["bc1", "bcrt1", "tb1"].iter().any(|&prefix| s.to_lowercase().starts_with(prefix)) { let address = Address::from_bech32_str(s)?; // We know that `U` is only ever `NetworkUnchecked` but the compiler does not. - Ok(Address(address.0, PhantomData::)) + Ok(Address::from_inner(address.into_inner())) } else if ["1", "2", "3", "m", "n"].iter().any(|&prefix| s.starts_with(prefix)) { let address = Address::from_base58_str(s)?; - Ok(Address(address.0, PhantomData::)) + Ok(Address::from_inner(address.into_inner())) } else { let hrp = match s.rfind('1') { Some(pos) => &s[..pos], diff --git a/bitcoin/src/blockdata/script/push_bytes.rs b/bitcoin/src/blockdata/script/push_bytes.rs index bae7902b3..f469290f0 100644 --- a/bitcoin/src/blockdata/script/push_bytes.rs +++ b/bitcoin/src/blockdata/script/push_bytes.rs @@ -35,33 +35,29 @@ mod primitive { } } - /// Byte slices that can be in Bitcoin script. - /// - /// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long. - /// This type represents slices that are guaranteed to be within the limit so they can be put in - /// the script safely. - #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - pub struct PushBytes([u8]); + internals::transparent_newtype! { + /// Byte slices that can be in Bitcoin script. + /// + /// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long. + /// This type represents slices that are guaranteed to be within the limit so they can be put in + /// the script safely. + #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct PushBytes([u8]); + + impl PushBytes { + /// Constructs a new `&PushBytes` without checking the length. + /// + /// The caller is responsible for checking that the length is less than the 2^32. + fn from_slice_unchecked(bytes: &_) -> &Self; + + /// Constructs a new `&mut PushBytes` without checking the length. + /// + /// The caller is responsible for checking that the length is less than the 2^32. + fn from_mut_slice_unchecked(bytes: &mut _) -> &mut Self; + } + } impl PushBytes { - /// Constructs a new `&PushBytes` without checking the length. - /// - /// The caller is responsible for checking that the length is less than the 2^32. - fn from_slice_unchecked(bytes: &[u8]) -> &Self { - // SAFETY: The conversion is sound because &[u8] and &PushBytes - // have the same layout (because of #[repr(transparent)] on PushBytes). - unsafe { &*(bytes as *const [u8] as *const PushBytes) } - } - - /// Constructs a new `&mut PushBytes` without checking the length. - /// - /// The caller is responsible for checking that the length is less than the 2^32. - fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self { - // SAFETY: The conversion is sound because &mut [u8] and &mut PushBytes - // have the same layout (because of #[repr(transparent)] on PushBytes). - unsafe { &mut *(bytes as *mut [u8] as *mut PushBytes) } - } /// Constructs an empty `&PushBytes`. pub fn empty() -> &'static Self { Self::from_slice_unchecked(&[]) } diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs index f8e8abe5b..06d2a72e0 100644 --- a/bitcoin/src/blockdata/witness.rs +++ b/bitcoin/src/blockdata/witness.rs @@ -10,15 +10,15 @@ use io::{BufRead, Write}; use crate::consensus::encode::{self, Error, ReadExt, WriteExt, MAX_VEC_SIZE}; use crate::consensus::{Decodable, Encodable}; use crate::crypto::ecdsa; +use crate::crypto::key::SerializedXOnlyPublicKey; use crate::prelude::Vec; #[cfg(doc)] use crate::script::ScriptExt as _; -use crate::taproot::{ - self, ControlBlock, LeafScript, LeafVersion, TAPROOT_ANNEX_PREFIX, TAPROOT_CONTROL_BASE_SIZE, - TAPROOT_LEAF_MASK, TaprootMerkleBranch, -}; +use crate::taproot::{self, ControlBlock, LeafScript, TAPROOT_ANNEX_PREFIX, TaprootMerkleBranch}; use crate::Script; +type BorrowedControlBlock<'a> = ControlBlock<&'a TaprootMerkleBranch, &'a SerializedXOnlyPublicKey>; + #[rustfmt::skip] // Keep public re-exports separate. #[doc(inline)] pub use primitives::witness::{Iter, Witness}; @@ -176,9 +176,8 @@ crate::internal_macros::define_extension_trait! { /// version. fn taproot_leaf_script(&self) -> Option> { match P2TrSpend::from_witness(self) { - Some(P2TrSpend::Script { leaf_script, control_block, .. }) if control_block.len() >= TAPROOT_CONTROL_BASE_SIZE => { - let version = LeafVersion::from_consensus(control_block[0] & TAPROOT_LEAF_MASK).ok()?; - Some(LeafScript { version, script: leaf_script, }) + Some(P2TrSpend::Script { leaf_script, control_block, .. }) => { + Some(LeafScript { version: control_block.leaf_version, script: leaf_script, }) }, _ => None, } @@ -191,7 +190,7 @@ crate::internal_macros::define_extension_trait! { /// 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]> { + fn taproot_control_block(&self) -> Option> { match P2TrSpend::from_witness(self) { Some(P2TrSpend::Script { control_block, .. }) => Some(control_block), _ => None, @@ -236,7 +235,7 @@ enum P2TrSpend<'a> { }, Script { leaf_script: &'a Script, - control_block: &'a [u8], + control_block: BorrowedControlBlock<'a>, annex: Option<&'a [u8]>, }, } @@ -275,17 +274,21 @@ impl<'a> P2TrSpend<'a> { // last one does NOT start with TAPROOT_ANNEX_PREFIX. This is handled in the catchall // arm. 3.. if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => { + let control_block = witness.get_back(1).expect("len > 1"); + let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?; let spend = P2TrSpend::Script { leaf_script: Script::from_bytes(witness.get_back(2).expect("len > 2")), - control_block: witness.get_back(1).expect("len > 1"), + control_block, annex: witness.last(), }; Some(spend) } _ => { + let control_block = witness.last().expect("len > 0"); + let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?; let spend = P2TrSpend::Script { leaf_script: Script::from_bytes(witness.get_back(1).expect("len > 1")), - control_block: witness.last().expect("len > 0"), + control_block, annex: None, }; Some(spend) @@ -324,6 +327,7 @@ mod test { use crate::consensus::{deserialize, encode, serialize}; use crate::hex::DisplayHex; use crate::sighash::EcdsaSighashType; + use crate::taproot::LeafVersion; use crate::Transaction; #[test] @@ -383,7 +387,7 @@ mod test { #[test] fn get_tapscript() { let tapscript = hex!("deadbeef"); - let control_block = hex!("02"); + let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // annex starting with 0x50 causes the branching logic. let annex = hex!("50"); @@ -431,7 +435,8 @@ mod test { #[test] fn get_control_block() { let tapscript = hex!("deadbeef"); - let control_block = hex!("02"); + let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + let expected_control_block = BorrowedControlBlock::decode_borrowed(&control_block).unwrap(); // annex starting with 0x50 causes the branching logic. let annex = hex!("50"); let signature = vec![0xff; 64]; @@ -441,15 +446,15 @@ mod test { let witness_key_spend_annex = Witness::from([&*signature, &annex]); // With or without annex, the tapscript should be returned. - assert_eq!(witness.taproot_control_block(), Some(&control_block[..])); - assert_eq!(witness_annex.taproot_control_block(), Some(&control_block[..])); + assert_eq!(witness.taproot_control_block().unwrap(), expected_control_block); + assert_eq!(witness_annex.taproot_control_block().unwrap(), expected_control_block); assert!(witness_key_spend_annex.taproot_control_block().is_none()) } #[test] fn get_annex() { let tapscript = hex!("deadbeef"); - let control_block = hex!("02"); + let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // annex starting with 0x50 causes the branching logic. let annex = hex!("50"); diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 9db307906..a2d8a0a7c 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -26,6 +26,7 @@ use crate::taproot::{TapNodeHash, TapTweakHash}; #[rustfmt::skip] // Keep public re-exports separate. pub use secp256k1::{constants, Keypair, Parity, Secp256k1, Verification, XOnlyPublicKey}; +pub use serialized_x_only::SerializedXOnlyPublicKey; #[cfg(feature = "rand-std")] pub use secp256k1::rand; @@ -1222,6 +1223,63 @@ impl fmt::Display for InvalidWifCompressionFlagError { #[cfg(feature = "std")] impl std::error::Error for InvalidWifCompressionFlagError {} +mod serialized_x_only { + internals::transparent_newtype! { + /// An array of bytes that's semantically an x-only public but was **not** validated. + /// + /// This can be useful when validation is not desired but semantics of the bytes should be + /// preserved. The validation can still happen using `to_validated()` method. + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct SerializedXOnlyPublicKey([u8; 32]); + + impl SerializedXOnlyPublicKey { + pub(crate) fn from_bytes_ref(bytes: &_) -> Self; + } + } + + impl SerializedXOnlyPublicKey { + /// Marks the supplied bytes as a serialized x-only public key. + pub const fn from_byte_array(bytes: [u8; 32]) -> Self { + Self(bytes) + } + + /// Returns the raw bytes. + pub const fn to_byte_array(self) -> [u8; 32] { + self.0 + } + + /// Returns a reference to the raw bytes. + pub const fn as_byte_array(&self) -> &[u8; 32] { + &self.0 + } + } +} + +impl SerializedXOnlyPublicKey { + /// Returns `XOnlyPublicKey` if the bytes are valid. + pub fn to_validated(self) -> Result { + XOnlyPublicKey::from_byte_array(self.as_byte_array()) + } +} + +impl AsRef<[u8; 32]> for SerializedXOnlyPublicKey { + fn as_ref(&self) -> &[u8; 32] { + self.as_byte_array() + } +} + +impl From<&SerializedXOnlyPublicKey> for SerializedXOnlyPublicKey { + fn from(borrowed: &SerializedXOnlyPublicKey) -> Self { + *borrowed + } +} + +impl fmt::Debug for SerializedXOnlyPublicKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.as_byte_array().as_hex(), f) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/bitcoin/src/taproot/merkle_branch/borrowed.rs b/bitcoin/src/taproot/merkle_branch/borrowed.rs index 58538f09d..6ca681e25 100644 --- a/bitcoin/src/taproot/merkle_branch/borrowed.rs +++ b/bitcoin/src/taproot/merkle_branch/borrowed.rs @@ -9,10 +9,16 @@ pub use privacy_boundary::TaprootMerkleBranch; mod privacy_boundary { use super::*; - /// The Merkle proof for inclusion of a tree in a Taproot tree hash. - #[repr(transparent)] - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct TaprootMerkleBranch([TapNodeHash]); + internals::transparent_newtype! { + /// The Merkle proof for inclusion of a tree in a Taproot tree hash. + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct TaprootMerkleBranch([TapNodeHash]); + + impl TaprootMerkleBranch { + pub(super) const fn from_hashes_unchecked(hashes: &_) -> &Self; + pub(super) fn from_mut_hashes_unchecked(hashes: &mut _) -> &mut Self; + } + } impl TaprootMerkleBranch { /// Returns a reference to the slice of hashes. @@ -22,18 +28,6 @@ mod privacy_boundary { /// Returns a reference to the mutable slice of hashes. #[inline] pub fn as_mut_slice(&mut self) -> &mut [TapNodeHash] { &mut self.0 } - - pub(super) const fn from_hashes_unchecked(hashes: &[TapNodeHash]) -> &Self { - unsafe { - &*(hashes as *const _ as *const Self) - } - } - - pub(super) fn from_mut_hashes_unchecked(hashes: &mut [TapNodeHash]) -> &mut Self { - unsafe { - &mut *(hashes as *mut _ as *mut Self) - } - } } } diff --git a/bitcoin/src/taproot/mod.rs b/bitcoin/src/taproot/mod.rs index b14264f24..15f188a10 100644 --- a/bitcoin/src/taproot/mod.rs +++ b/bitcoin/src/taproot/mod.rs @@ -22,7 +22,7 @@ use io::Write; use secp256k1::{Scalar, Secp256k1}; use crate::consensus::Encodable; -use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey}; +use crate::crypto::key::{SerializedXOnlyPublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey}; use crate::prelude::{BTreeMap, BTreeSet, BinaryHeap, Vec}; use crate::{Script, ScriptBuf}; @@ -1141,13 +1141,13 @@ impl<'leaf> ScriptLeaf<'leaf> { /// Control block data structure used in Tapscript satisfaction. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct ControlBlock where Branch: ?Sized { +pub struct ControlBlock where Branch: ?Sized { /// The tapleaf version. pub leaf_version: LeafVersion, /// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY). pub output_key_parity: secp256k1::Parity, /// The internal key. - pub internal_key: UntweakedPublicKey, + pub internal_key: Key, /// The Merkle proof of a script associated with this leaf. pub merkle_branch: Branch, } @@ -1166,6 +1166,24 @@ impl ControlBlock { /// - [`TaprootError::InvalidInternalKey`] if internal key is invalid (first 32 bytes after the parity byte). /// - [`TaprootError::InvalidMerkleTreeDepth`] if Merkle tree is too deep (more than 128 levels). pub fn decode(sl: &[u8]) -> Result { + use alloc::borrow::ToOwned; + + let ControlBlock { + leaf_version, + output_key_parity, + internal_key, + merkle_branch, + } = ControlBlock::<&TaprootMerkleBranch, &SerializedXOnlyPublicKey>::decode_borrowed(sl)?; + + let internal_key = internal_key.to_validated().map_err(TaprootError::InvalidInternalKey)?; + let merkle_branch = merkle_branch.to_owned(); + + Ok(ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch }) + } +} + +impl ControlBlock { + pub(crate) fn decode_borrowed<'a>(sl: &'a [u8]) -> Result where B: From<&'a TaprootMerkleBranch>, K: From<&'a SerializedXOnlyPublicKey> { let (base, merkle_branch) = sl.split_first_chunk::() .ok_or(InvalidControlBlockSizeError(sl.len()))?; @@ -1177,9 +1195,8 @@ impl ControlBlock { }; let leaf_version = LeafVersion::from_consensus(first & TAPROOT_LEAF_MASK)?; - let internal_key = UntweakedPublicKey::from_byte_array(internal_key) - .map_err(TaprootError::InvalidInternalKey)?; - let merkle_branch = TaprootMerkleBranchBuf::decode(merkle_branch)?; + let internal_key = SerializedXOnlyPublicKey::from_bytes_ref(internal_key).into(); + let merkle_branch = TaprootMerkleBranch::decode(merkle_branch)?.into(); Ok(ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch }) } } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 5e9599322..19945b46c 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -117,10 +117,21 @@ pub(crate) use general_hash_type; macro_rules! hash_type_no_default { ($bits:expr, $reverse:expr, $doc:literal) => { - #[doc = $doc] - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[repr(transparent)] - pub struct Hash([u8; $bits / 8]); + internals::transparent_newtype! { + #[doc = $doc] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Hash([u8; $bits / 8]); + + impl Hash { + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &_) -> &Self; + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; + } + } impl Hash { const fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) } @@ -130,20 +141,6 @@ macro_rules! hash_type_no_default { Self::internal_new(bytes) } - /// Zero cost conversion between a fixed length byte array shared reference and - /// a shared reference to this Hash type. - pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] - unsafe { &*(bytes as *const _ as *const Self) } - } - - /// Zero cost conversion between a fixed length byte array exclusive reference and - /// an exclusive reference to this Hash type. - pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] - unsafe { &mut *(bytes as *mut _ as *mut Self) } - } - /// Copies a byte slice into a hash object. #[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")] #[allow(deprecated_in_future)] // Because of `FromSliceError`. diff --git a/hashes/src/sha256t/mod.rs b/hashes/src/sha256t/mod.rs index d5acd5edf..526892db2 100644 --- a/hashes/src/sha256t/mod.rs +++ b/hashes/src/sha256t/mod.rs @@ -43,33 +43,30 @@ pub trait Tag { const MIDSTATE: sha256::Midstate; } -/// Output of the SHA256t hash function. -#[repr(transparent)] -pub struct Hash([u8; 32], PhantomData); +internals::transparent_newtype! { + /// Output of the SHA256t hash function. + pub struct Hash(PhantomData, [u8; 32]); + + impl Hash { + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &_) -> &Self; + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; + } +} impl Hash where T: Tag, { - const fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, PhantomData) } + const fn internal_new(arr: [u8; 32]) -> Self { Hash(PhantomData, arr) } /// Constructs a new hash from the underlying byte array. pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self::internal_new(bytes) } - /// Zero cost conversion between a fixed length byte array shared reference and - /// a shared reference to this Hash type. - pub fn from_bytes_ref(bytes: &[u8; 32]) -> &Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; 32] - unsafe { &*(bytes as *const _ as *const Self) } - } - - /// Zero cost conversion between a fixed length byte array exclusive reference and - /// an exclusive reference to this Hash type. - pub fn from_bytes_mut(bytes: &mut [u8; 32]) -> &mut Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; 32] - unsafe { &mut *(bytes as *mut _ as *mut Self) } - } - /// Copies a byte slice into a hash object. #[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")] #[allow(deprecated_in_future)] // Because of `FromSliceError`. @@ -117,10 +114,10 @@ where } /// Returns the underlying byte array. - pub const fn to_byte_array(self) -> [u8; 32] { self.0 } + pub const fn to_byte_array(self) -> [u8; 32] { self.1 } /// Returns a reference to the underlying byte array. - pub const fn as_byte_array(&self) -> &[u8; 32] { &self.0 } + pub const fn as_byte_array(&self) -> &[u8; 32] { &self.1 } } impl Copy for Hash {} @@ -128,7 +125,7 @@ impl Clone for Hash { fn clone(&self) -> Self { *self } } impl PartialEq for Hash { - fn eq(&self, other: &Hash) -> bool { self.0 == other.0 } + fn eq(&self, other: &Hash) -> bool { self.as_byte_array() == other.as_byte_array() } } impl Eq for Hash {} impl PartialOrd for Hash { @@ -137,10 +134,10 @@ impl PartialOrd for Hash { } } impl Ord for Hash { - fn cmp(&self, other: &Hash) -> cmp::Ordering { cmp::Ord::cmp(&self.0, &other.0) } + fn cmp(&self, other: &Hash) -> cmp::Ordering { cmp::Ord::cmp(&self.as_byte_array(), &other.as_byte_array()) } } impl core::hash::Hash for Hash { - fn hash(&self, h: &mut H) { self.0.hash(h) } + fn hash(&self, h: &mut H) { self.as_byte_array().hash(h) } } crate::internal_macros::hash_trait_impls!(256, false, T: Tag); diff --git a/internals/src/lib.rs b/internals/src/lib.rs index c2e2ce708..35c179142 100644 --- a/internals/src/lib.rs +++ b/internals/src/lib.rs @@ -35,6 +35,12 @@ pub mod rust_version { include!(concat!(env!("OUT_DIR"), "/rust_version.rs")); } +#[doc(hidden)] +pub mod _export { + #[cfg(feature = "alloc")] + pub extern crate alloc; +} + pub mod array; pub mod array_vec; pub mod compact_size; diff --git a/internals/src/macros.rs b/internals/src/macros.rs index b4c95f275..b23725a83 100644 --- a/internals/src/macros.rs +++ b/internals/src/macros.rs @@ -37,3 +37,211 @@ macro_rules! impl_to_hex_from_lower_hex { } }; } + +/// Creates a transparent wrapper around an inner type and soundly implements reference casts. +/// +/// This macro takes care of several issues related to newtypes that need to allow casting their +/// inner types to themselves: +/// +/// * It makes sure to put repr(transparent) on the type +/// * It optionally implements conversions from `&`, `&mut`, `Box`, `Rc`, `Arc` +/// * It makes sure to put `#[inline]` on all of these conversions since they are trivial +/// * It makes sure the reference cast is const +/// * It makes sure the `Arc` conversion is conditioned on `target_has_atomic = "ptr"` +/// +/// Usage: just type the struct inside the macro as you would implementing it manually except leave +/// `#[repr(transparent)]` out. Then add an impl block for the just-defined type containing function +/// declarations that take a reference/smart pointer to `_` (use literal underscore; e.g. `&_` for +/// shared references) and return `Self` behind the appropriate "pointer" type. Do not write the +/// body, just semicolon. +/// +/// The `alloc` types MUST NOT have import paths and don't need imports. +#[macro_export] +macro_rules! transparent_newtype { + ( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $newtype:tt$(<$gen:ident $(= $default:ty)?>)?($($fields:tt)+) $(where $($where_ty:ty: $bound:path),* $(,)?)?; + + impl$(<$gen2:tt>)? $newtype2:ident$(<$gen3:tt>)? { + $( + $(#[$($fn_attr:tt)*])* + $fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty; + )* + } + ) => { + $crate::_check_tts_eq!($newtype2, $newtype, "the type name in the impl block doesn't match the struct name"); + $( + // WARNING: renaming has to be disabled for soundness! + // If it weren't it'd be possible to make the type inside struct not match the one passed + // to functions. In principle we could also omit the generics but that'd be confusing for + // readers. + $crate::_check_tts_eq!($gen2, $gen, "the name of the left generic parameter in impl block doesn't match the one on struct"); + $crate::_check_tts_eq!($gen3, $gen, "the name of the right generic parameter in impl block doesn't match the one on struct"); + )? + $(#[$($struct_attr)*])* + #[repr(transparent)] + $vis struct $newtype$(<$gen $(= $default)?>)?($($fields)+) $(where $($where_ty: $bound),*)?; + + impl$(<$gen2>)? $newtype$(<$gen3>)? $(where $($where_ty: $bound),*)? { + $crate::_transparent_ref_conversions! { + $crate::_transparent_newtype_inner_type!($($fields)+); + $( + $(#[$($fn_attr)*])* + $fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty; + )+ + } + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_ref_conversions { + ( + $inner:ty; + $( + $(#[$($fn_attr:tt)*])* + $fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty; + )+ + ) => { + $( + $crate::_transparent_ref_conversion! { + $inner; + $(#[$($fn_attr)*])* + $fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty; + } + )+ + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_ref_conversion { + ( + $inner:ty; + $(#[$($from_ref_attr:tt)*])* + $from_ref_vis:vis fn $from_ref:ident($from_ref_arg_name:ident: &_) -> $fn_ret_ty:ty; + ) => { + #[inline] + $(#[$($from_ref_attr)*])* + $from_ref_vis const fn $from_ref($from_ref_arg_name: &$inner) -> &Self { + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from a reference. (Notice repr(transparent).) + // The lifetime of the input reference matches the lifetime of the returned reference. + unsafe { &*($from_ref_arg_name as *const $inner as *const Self) } + } + }; + ( + $inner:ty; + $(#[$($from_mut_attr:tt)*])* + $from_mut_vis:vis fn $from_mut:ident($from_mut_arg_name:ident: &mut _) -> $fn_ret_ty:ty; + ) => { + #[inline] + $(#[$($from_mut_attr)*])* + $from_mut_vis fn $from_mut($from_mut_arg_name: &mut $inner) -> &mut Self { + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from a reference. (Notice repr(transparent).) + // The lifetime of the input reference matches the lifetime of the returned reference. + unsafe { &mut *($from_mut_arg_name as *mut $inner as *mut Self) } + } + }; + ( + $inner:ty; + $(#[$($from_box_attr:tt)*])* + $from_box_vis:vis fn $from_box:ident($from_box_arg_name:ident: Box<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_box_attr)*])* + #[inline] + $from_box_vis fn $from_box($from_box_arg_name: $crate::_export::alloc::boxed::Box<$inner>) -> $crate::_export::alloc::boxed::Box { + let ptr = $crate::_export::alloc::boxed::Box::into_raw($from_box_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::boxed::Box::from_raw(ptr as *mut Self) } + } + } + }; + + ( + $inner:ty; + $(#[$($from_rc_attr:tt)*])* + $from_rc_vis:vis fn $from_rc:ident($from_rc_arg_name:ident: Rc<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_rc_attr)*])* + #[inline] + $from_rc_vis fn $from_rc($from_rc_arg_name: $crate::_export::alloc::rc::Rc<$inner>) -> $crate::_export::alloc::rc::Rc { + let ptr = $crate::_export::alloc::rc::Rc::into_raw($from_rc_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::rc::Rc::from_raw(ptr as *mut Self) } + } + } + }; + + ( + $inner:ty; + $(#[$($from_arc_attr:tt)*])* + $from_arc_vis:vis fn $from_arc:ident($from_arc_arg_name:ident: Arc<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_arc_attr)*])* + #[cfg(target_has_atomic = "ptr")] + #[inline] + $from_arc_vis fn $from_arc($from_arc_arg_name: $crate::_export::alloc::sync::Arc<$inner>) -> $crate::_export::alloc::sync::Arc { + let ptr = $crate::_export::alloc::sync::Arc::into_raw($from_arc_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::sync::Arc::from_raw(ptr as *mut Self) } + } + } + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _check_tts_eq { + ($left:tt, $right:tt, $message:literal) => { + macro_rules! token_eq { + ($right) => {}; + ($any:tt) => { compile_error!($message) }; + } + token_eq!($left); + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_newtype_inner_type { + ($(#[$($field_attr:tt)*])* $inner:ty) => { + $inner + }; + ($(#[$($phantom_attr:tt)*])* PhantomData<$phantom:ty>, $(#[$($field_attr:tt)*])* $inner:ty) => { + $inner + }; +} + +/// Emits given tokens only if the `alloc` feature **in this crate** is enabled. +/// +/// (The feature is currently enabled.) +#[cfg(feature = "alloc")] +#[doc(hidden)] +#[macro_export] +macro_rules! _emit_alloc { + ($($tokens:tt)*) => { $($tokens)* }; +} + +/// Emits given tokens only if the `alloc` feature **in this crate** is enabled. +/// +/// (The feature is currently disabled.) +#[cfg(not(feature = "alloc"))] +#[doc(hidden)] +#[macro_export] +macro_rules! _emit_alloc { + ($($tokens:tt)*) => {}; +} diff --git a/io/src/bridge.rs b/io/src/bridge.rs index fc49a0771..816820a2a 100644 --- a/io/src/bridge.rs +++ b/io/src/bridge.rs @@ -1,35 +1,26 @@ // SPDX-License-Identifier: CC0-1.0 -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - use internals::rust_version; -/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits. -#[repr(transparent)] -#[derive(Debug)] -pub struct FromStd(T); +internals::transparent_newtype! { + /// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits. + #[derive(Debug)] + pub struct FromStd(T); + + impl FromStd { + /// Wraps a mutable reference to I/O type. + pub fn new_mut(inner: &mut _) -> &mut Self; + + /// Wraps a boxed I/O type. + pub fn new_boxed(inner: Box<_>) -> Box; + } +} impl FromStd { /// Wraps an I/O type. #[inline] pub const fn new(inner: T) -> Self { Self(inner) } - /// Wraps a mutable reference to I/O type. - #[inline] - pub fn new_mut(inner: &mut T) -> &mut Self { - // SAFETY: the type is repr(transparent) and the lifetimes match - unsafe { &mut *(inner as *mut _ as *mut Self) } - } - - /// Wraps a boxed I/O type. - #[cfg(feature = "alloc")] - #[inline] - pub fn new_boxed(inner: Box) -> Box { - // SAFETY: the type is repr(transparent) and the pointer is created from Box - unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) } - } - /// Returns the wrapped value. #[inline] pub fn into_inner(self) -> T { self.0 } @@ -117,31 +108,25 @@ impl std::io::Write for FromStd { fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { self.0.write_all(buf) } } -/// A bridging wrapper providing the std traits for types that already implement our traits. -#[repr(transparent)] -#[derive(Debug)] -pub struct ToStd(T); +internals::transparent_newtype! { + /// A bridging wrapper providing the std traits for types that already implement our traits. + #[derive(Debug)] + pub struct ToStd(T); + + impl ToStd { + /// Wraps a mutable reference to I/O type. + pub fn new_mut(inner: &mut _) -> &mut Self; + + /// Wraps a boxed I/O type. + pub fn new_boxed(inner: Box<_>) -> Box; + } +} impl ToStd { /// Wraps an I/O type. #[inline] pub const fn new(inner: T) -> Self { Self(inner) } - /// Wraps a mutable reference to I/O type. - #[inline] - pub fn new_mut(inner: &mut T) -> &mut Self { - // SAFETY: the type is repr(transparent) and the lifetimes match - unsafe { &mut *(inner as *mut _ as *mut Self) } - } - - /// Wraps a boxed I/O type. - #[cfg(feature = "alloc")] - #[inline] - pub fn new_boxed(inner: Box) -> Box { - // SAFETY: the type is repr(transparent) and the pointer is created from Box - unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) } - } - /// Returns the wrapped value. #[inline] pub fn into_inner(self) -> T { self.0 } diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs index ece38f6ee..4f3bca28c 100644 --- a/primitives/src/script/borrowed.rs +++ b/primitives/src/script/borrowed.rs @@ -10,54 +10,67 @@ use arbitrary::{Arbitrary, Unstructured}; use super::ScriptBuf; use crate::prelude::{Box, ToOwned, Vec}; -/// Bitcoin script slice. -/// -/// *[See also the `bitcoin::script` module](super).* -/// -/// `Script` is a script slice, the most primitive script type. It's usually seen in its borrowed -/// form `&Script`. It is always encoded as a series of bytes representing the opcodes and data -/// pushes. -/// -/// ## Validity -/// -/// `Script` does not have any validity invariants - it's essentially just a marked slice of -/// bytes. This is similar to [`Path`](std::path::Path) vs [`OsStr`](std::ffi::OsStr) where they -/// are trivially cast-able to each-other and `Path` doesn't guarantee being a usable FS path but -/// having a newtype still has value because of added methods, readability and basic type checking. -/// -/// Although at least data pushes could be checked not to overflow the script, bad scripts are -/// allowed to be in a transaction (outputs just become unspendable) and there even are such -/// transactions in the chain. Thus we must allow such scripts to be placed in the transaction. -/// -/// ## Slicing safety -/// -/// Slicing is similar to how `str` works: some ranges may be incorrect and indexing by -/// `usize` is not supported. However, as opposed to `std`, we have no way of checking -/// correctness without causing linear complexity so there are **no panics on invalid -/// ranges!** If you supply an invalid range, you'll get a garbled script. -/// -/// The range is considered valid if it's at a boundary of instruction. Care must be taken -/// especially with push operations because you could get a reference to arbitrary -/// attacker-supplied bytes that look like a valid script. -/// -/// It is recommended to use `.instructions()` method to get an iterator over script -/// instructions and work with that instead. -/// -/// ## Memory safety -/// -/// The type is `#[repr(transparent)]` for internal purposes only! -/// No consumer crate may rely on the representation of the struct! -/// -/// ## References -/// -/// -/// ### Bitcoin Core References -/// -/// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410) -/// -#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct Script([u8]); +internals::transparent_newtype! { + /// Bitcoin script slice. + /// + /// *[See also the `bitcoin::script` module](super).* + /// + /// `Script` is a script slice, the most primitive script type. It's usually seen in its borrowed + /// form `&Script`. It is always encoded as a series of bytes representing the opcodes and data + /// pushes. + /// + /// ## Validity + /// + /// `Script` does not have any validity invariants - it's essentially just a marked slice of + /// bytes. This is similar to [`Path`](std::path::Path) vs [`OsStr`](std::ffi::OsStr) where they + /// are trivially cast-able to each-other and `Path` doesn't guarantee being a usable FS path but + /// having a newtype still has value because of added methods, readability and basic type checking. + /// + /// Although at least data pushes could be checked not to overflow the script, bad scripts are + /// allowed to be in a transaction (outputs just become unspendable) and there even are such + /// transactions in the chain. Thus we must allow such scripts to be placed in the transaction. + /// + /// ## Slicing safety + /// + /// Slicing is similar to how `str` works: some ranges may be incorrect and indexing by + /// `usize` is not supported. However, as opposed to `std`, we have no way of checking + /// correctness without causing linear complexity so there are **no panics on invalid + /// ranges!** If you supply an invalid range, you'll get a garbled script. + /// + /// The range is considered valid if it's at a boundary of instruction. Care must be taken + /// especially with push operations because you could get a reference to arbitrary + /// attacker-supplied bytes that look like a valid script. + /// + /// It is recommended to use `.instructions()` method to get an iterator over script + /// instructions and work with that instead. + /// + /// ## Memory safety + /// + /// The type is `#[repr(transparent)]` for internal purposes only! + /// No consumer crate may rely on the representation of the struct! + /// + /// ## References + /// + /// + /// ### Bitcoin Core References + /// + /// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410) + /// + #[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] + pub struct Script([u8]); + + impl Script { + /// Treat byte slice as `Script` + pub const fn from_bytes(bytes: &_) -> &Self; + + /// Treat mutable byte slice as `Script` + pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; + + pub(crate) fn from_boxed_bytes(bytes: Box<_>) -> Box; + pub(crate) fn from_rc_bytes(bytes: Rc<_>) -> Rc; + pub(crate) fn from_arc_bytes(bytes: Arc<_>) -> Arc; + } +} impl Default for &Script { #[inline] @@ -76,28 +89,6 @@ impl Script { #[inline] pub const fn new() -> &'static Self { Self::from_bytes(&[]) } - /// Treat byte slice as `Script` - #[inline] - pub const fn from_bytes(bytes: &[u8]) -> &Self { - // SAFETY: copied from `std` - // The pointer was just created from a reference which is still alive. - // Casting slice pointer to a transparent struct wrapping that slice is sound (same - // layout). - unsafe { &*(bytes as *const [u8] as *const Self) } - } - - /// Treat mutable byte slice as `Script` - #[inline] - pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { - // SAFETY: copied from `std` - // The pointer was just created from a reference which is still alive. - // Casting slice pointer to a transparent struct wrapping that slice is sound (same - // layout). - // Function signature prevents callers from accessing `bytes` while the returned reference - // is alive. - unsafe { &mut *(bytes as *mut [u8] as *mut Self) } - } - /// Returns the script data as a byte slice. #[inline] pub const fn as_bytes(&self) -> &[u8] { &self.0 } diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs index c263b4d68..2ad34017c 100644 --- a/primitives/src/script/mod.rs +++ b/primitives/src/script/mod.rs @@ -277,24 +277,14 @@ impl<'a> From<&'a Script> for Cow<'a, Script> { impl<'a> From<&'a Script> for Arc