What changed, and why it matters
This commit is a routine code reorganization: it moves the WitnessProgram type and its error handling from the main bitcoin crate into a new bitcoin-addresses sub-crate, then re-exports it so existing users still see the same public API. There is no functional change, no bug fix, and no security relevance visible in the diff.
No security action required. Treat as normal refactoring/reorganization.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change relocates addresses/src/witness_program.rs from bitcoin/src/blockdata/script/witness_program.rs. The implementation is essentially identical, with only import paths adjusted to pull FullPublicKey, TweakedPublicKey, UntweakedPublicKey from bitcoin-crypto, WScriptHash/WitnessScript/WitnessScriptSizeError from bitcoin-primitives, TapNodeHash/TapTweak from bitcoin-taproot-primitives, and ArrayVec from bitcoin-internals. bitcoin/Cargo.toml adds a dependency on bitcoin-addresses, and bitcoin/src/blockdata/script/mod.rs re-exports addresses::witness_program. The public API surface remains the same.
Changed components
bitcoin/src/blockdata/script/witness_program.rs (deleted)addresses/src/witness_program.rs (new)bitcoin/Cargo.tomladdresses/Cargo.tomlbitcoin/src/blockdata/script/mod.rsbitcoin/src/lib.rsInspect captured patch +258 / −236
diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock
index 14dc50be..cedcfcf6 100644
--- a/Cargo-minimal.lock
+++ b/Cargo-minimal.lock
@@ -81,6 +81,7 @@ dependencies = [
"base64",
"bech32",
"bincode",
+ "bitcoin-addresses",
"bitcoin-consensus-encoding 1.0.0",
"bitcoin-crypto",
"bitcoin-internals 0.5.0",
@@ -102,6 +103,12 @@ dependencies = [
[[package]]
name = "bitcoin-addresses"
version = "0.0.0"
+dependencies = [
+ "bitcoin-crypto",
+ "bitcoin-internals 0.5.0",
+ "bitcoin-primitives",
+ "bitcoin-taproot-primitives",
+]
[[package]]
name = "bitcoin-bip158"
diff --git a/Cargo-recent.lock b/Cargo-recent.lock
index 7dc949ad..4afc7acf 100644
--- a/Cargo-recent.lock
+++ b/Cargo-recent.lock
@@ -80,6 +80,7 @@ dependencies = [
"base64",
"bech32",
"bincode",
+ "bitcoin-addresses",
"bitcoin-consensus-encoding 1.0.0",
"bitcoin-crypto",
"bitcoin-internals 0.5.0",
@@ -101,6 +102,12 @@ dependencies = [
[[package]]
name = "bitcoin-addresses"
version = "0.0.0"
+dependencies = [
+ "bitcoin-crypto",
+ "bitcoin-internals 0.5.0",
+ "bitcoin-primitives",
+ "bitcoin-taproot-primitives",
+]
[[package]]
name = "bitcoin-bip158"
diff --git a/addresses/Cargo.toml b/addresses/Cargo.toml
index 3acd881c..fea99d3d 100644
--- a/addresses/Cargo.toml
+++ b/addresses/Cargo.toml
@@ -15,10 +15,14 @@ exclude = ["tests", "contrib"]
[features]
default = ["std"]
-std = ["alloc"]
-alloc = []
+std = ["alloc", "crypto/std", "internals/std", "primitives/std", "taproot_primitives/std"]
+alloc = ["crypto/alloc", "internals/alloc", "primitives/alloc", "taproot_primitives/alloc"]
[dependencies]
+crypto = { package = "bitcoin-crypto", path = "../crypto", version = "0.2.0", default-features = false, features = [] }
+internals = { package = "bitcoin-internals", path = "../internals", version = "0.5.0", features = ["hex"] }
+taproot_primitives = { package = "bitcoin-taproot-primitives", path = "../taproot-primitives", version = "0.1.0", default-features = false, features = [] }
+primitives = { package = "bitcoin-primitives", path = "../primitives", version = "0.102.0", default-features = false, features = ["hex"] }
[dev-dependencies]
diff --git a/addresses/src/lib.rs b/addresses/src/lib.rs
index 625bfffa..58655443 100644
--- a/addresses/src/lib.rs
+++ b/addresses/src/lib.rs
@@ -21,3 +21,6 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
+
+#[cfg(feature = "alloc")]
+pub mod witness_program;
diff --git a/addresses/src/witness_program.rs b/addresses/src/witness_program.rs
new file mode 100644
index 00000000..a299c305
--- /dev/null
+++ b/addresses/src/witness_program.rs
@@ -0,0 +1,230 @@
+//! The segregated witness program as defined by [BIP-0141].
+//!
+//! > A scriptPubKey (or redeemScript as defined in BIP-0016/P2SH) that consists of a 1-byte push
+//! > opcode (for 0 to 16) followed by a data push between 2 and 40 bytes gets a new special
+//! > meaning. The value of the first push is called the "version byte". The following byte
+//! > vector pushed is called the "witness program".
+//!
+//! [BIP-0141]: <https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki>
+
+use crypto::key::{FullPublicKey, TweakedPublicKey, UntweakedPublicKey};
+use internals::array_vec::ArrayVec;
+use primitives::script::{PushBytes, WScriptHash, WitnessScript, WitnessScriptSizeError};
+use primitives::witness_version::WitnessVersion;
+use taproot_primitives::{TapNodeHash, TapTweak as _};
+
+#[rustfmt::skip] // Keep public re-exports separate.
+#[doc(no_inline)]
+pub use self::error::Error;
+
+/// The minimum byte size of a segregated witness program.
+pub const MIN_SIZE: usize = 2;
+
+/// The maximum byte size of a segregated witness program.
+pub const MAX_SIZE: usize = 40;
+
+/// The P2A program which is given by 0x4e73.
+pub(crate) const P2A_PROGRAM: [u8; 2] = [78, 115];
+
+/// The segregated witness program.
+///
+/// The segregated witness program is technically only the program bytes _excluding_ the witness
+/// version, however we maintain length invariants on the `program` that are governed by the version
+/// number, therefore we carry the version number around along with the program bytes.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct WitnessProgram {
+ /// The SegWit version associated with this witness program.
+ version: WitnessVersion,
+ /// The witness program (between 2 and 40 bytes).
+ program: ArrayVec<u8, MAX_SIZE>,
+}
+
+impl WitnessProgram {
+ /// Constructs a new witness program, copying the content from the given byte slice.
+ pub fn new(version: WitnessVersion, bytes: &[u8]) -> Result<Self, Error> {
+ let program_len = bytes.len();
+ if program_len < MIN_SIZE || program_len > MAX_SIZE {
+ return Err(Error::InvalidLength(program_len));
+ }
+
+ // Specific SegWit v0 check. These addresses can never spend funds sent to them.
+ if version == WitnessVersion::V0 && (program_len != 20 && program_len != 32) {
+ return Err(Error::InvalidSegwitV0Length(program_len));
+ }
+
+ let program = ArrayVec::from_slice(bytes);
+ Ok(Self { version, program })
+ }
+
+ /// Constructs a new [`WitnessProgram`] from a 20 byte pubkey hash.
+ fn new_p2wpkh(program: [u8; 20]) -> Self {
+ Self { version: WitnessVersion::V0, program: ArrayVec::from_slice(&program) }
+ }
+
+ /// Constructs a new [`WitnessProgram`] from a 32 byte script hash.
+ fn new_p2wsh(program: [u8; 32]) -> Self {
+ Self { version: WitnessVersion::V0, program: ArrayVec::from_slice(&program) }
+ }
+
+ /// Constructs a new [`WitnessProgram`] from a 32 byte serialized Taproot x-only pubkey.
+ fn new_p2tr(program: [u8; 32]) -> Self {
+ Self { version: WitnessVersion::V1, program: ArrayVec::from_slice(&program) }
+ }
+
+ /// Constructs a new [`WitnessProgram`] from `pk` for a P2WPKH output.
+ pub fn p2wpkh(pk: FullPublicKey) -> Self {
+ let hash = pk.wpubkey_hash();
+ Self::new_p2wpkh(hash.to_byte_array())
+ }
+
+ /// Constructs a new [`WitnessProgram`] from `script` for a P2WSH output.
+ pub fn p2wsh(script: &WitnessScript) -> Result<Self, WitnessScriptSizeError> {
+ WScriptHash::from_script(script).map(Self::p2wsh_from_hash)
+ }
+
+ /// Constructs a new [`WitnessProgram`] from `script` for a P2WSH output.
+ pub fn p2wsh_from_hash(hash: WScriptHash) -> Self { Self::new_p2wsh(hash.to_byte_array()) }
+
+ /// Constructs a new [`WitnessProgram`] from an untweaked key for a P2TR output.
+ ///
+ /// This function applies BIP-0341 key-tweaking to the untweaked
+ /// key using the merkle root, if it's present.
+ pub fn p2tr<K: Into<UntweakedPublicKey>>(
+ internal_key: K,
+ merkle_root: Option<TapNodeHash>,
+ ) -> Self {
+ let internal_key = internal_key.into();
+ let output_key = internal_key.tap_tweak(merkle_root);
+ let (pubkey, _) = output_key.as_x_only_public_key().serialize();
+ Self::new_p2tr(pubkey)
+ }
+
+ /// Constructs a new [`WitnessProgram`] from a tweaked key for a P2TR output.
+ pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Self {
+ let (pubkey, _) = output_key.as_x_only_public_key().serialize();
+ Self::new_p2tr(pubkey)
+ }
+
+ /// Constructs a new [`WitnessProgram`] for a P2A output.
+ pub const fn p2a() -> Self {
+ Self { version: WitnessVersion::V1, program: ArrayVec::from_slice(&P2A_PROGRAM) }
+ }
+
+ /// Returns the witness program version.
+ pub fn version(&self) -> WitnessVersion { self.version }
+
+ /// Returns the witness program.
+ pub fn program(&self) -> &PushBytes {
+ self.program
+ .as_slice()
+ .try_into()
+ .expect("witness programs are always smaller than max size of PushBytes")
+ }
+
+ /// Returns true if this witness program is for a P2WPKH output.
+ pub fn is_p2wpkh(&self) -> bool {
+ self.version == WitnessVersion::V0 && self.program.len() == 20
+ }
+
+ /// Returns true if this witness program is for a P2WSH output.
+ pub fn is_p2wsh(&self) -> bool {
+ self.version == WitnessVersion::V0 && self.program.len() == 32
+ }
+
+ /// Returns true if this witness program is for a P2TR output.
+ pub fn is_p2tr(&self) -> bool { self.version == WitnessVersion::V1 && self.program.len() == 32 }
+
+ /// Returns true if this witness program is for a P2A output.
+ pub fn is_p2a(&self) -> bool {
+ self.version == WitnessVersion::V1 && self.program == P2A_PROGRAM
+ }
+}
+
+/// Error types for witness programs.
+pub mod error {
+ use core::convert::Infallible;
+ use core::fmt;
+
+ /// Witness program error.
+ #[derive(Clone, Debug, PartialEq, Eq)]
+ #[non_exhaustive]
+ pub enum Error {
+ /// The witness program must be between 2 and 40 bytes in length.
+ InvalidLength(usize),
+ /// A v0 witness program must be either of length 20 or 32.
+ InvalidSegwitV0Length(usize),
+ }
+
+ impl From<Infallible> for Error {
+ fn from(never: Infallible) -> Self { match never {} }
+ }
+
+ impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::InvalidLength(len) =>
+ write!(f, "witness program must be between 2 and 40 bytes: length={}", len),
+ Self::InvalidSegwitV0Length(len) =>
+ write!(f, "a v0 witness program must be either 20 or 32 bytes: length={}", len),
+ }
+ }
+ }
+
+ #[cfg(feature = "std")]
+ impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Self::InvalidLength(_) | Self::InvalidSegwitV0Length(_) => None,
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn witness_program_is_too_short() {
+ let arbitrary_bytes = [0x00; MIN_SIZE - 1];
+ assert!(WitnessProgram::new(WitnessVersion::V15, &arbitrary_bytes).is_err()); // Arbitrary version
+ }
+
+ #[test]
+ fn witness_program_is_too_long() {
+ let arbitrary_bytes = [0x00; MAX_SIZE + 1];
+ assert!(WitnessProgram::new(WitnessVersion::V15, &arbitrary_bytes).is_err()); // Arbitrary version
+ }
+
+ #[test]
+ fn valid_v0_witness_programs() {
+ let arbitrary_bytes = [0x00; MAX_SIZE];
+
+ for size in MIN_SIZE..=MAX_SIZE {
+ let program = WitnessProgram::new(WitnessVersion::V0, &arbitrary_bytes[..size]);
+
+ if size == 20 {
+ assert!(program.expect("valid witness program").is_p2wpkh());
+ continue;
+ }
+ if size == 32 {
+ assert!(program.expect("valid witness program").is_p2wsh());
+ continue;
+ }
+ assert!(program.is_err());
+ }
+ }
+
+ #[test]
+ fn valid_v1_witness_programs() {
+ let arbitrary_bytes = [0x00; 32];
+ assert!(WitnessProgram::new(WitnessVersion::V1, &arbitrary_bytes)
+ .expect("valid witness program")
+ .is_p2tr());
+
+ let p2a_bytes = [78, 115];
+ assert!(WitnessProgram::new(WitnessVersion::V1, &p2a_bytes)
+ .expect("valid witness program")
+ .is_p2a());
+ }
+}
diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml
index 66d86448..3df5ac1a 100644
--- a/bitcoin/Cargo.toml
+++ b/bitcoin/Cargo.toml
@@ -17,7 +17,7 @@ exclude = ["tests", "contrib"]
# If you change features or optional dependencies in any way please update the "# Cargo features" section in lib.rs as well.
[features]
default = [ "std", "secp-recovery" ]
-std = ["base58/std", "bech32/std", "crypto/std", "key-expression/std", "encoding/std", "hashes/std", "hex/std", "internals/std", "io/std", "network/std", "primitives/std", "secp256k1/std", "taproot-primitives/std", "units/std", "base64?/std", "bitcoinconsensus?/std"]
+std = ["addresses/std", "base58/std", "bech32/std", "crypto/std", "key-expression/std", "encoding/std", "hashes/std", "hex/std", "internals/std", "io/std", "network/std", "primitives/std", "secp256k1/std", "taproot-primitives/std", "units/std", "base64?/std", "bitcoinconsensus?/std"]
rand = ["secp256k1/rand", "crypto/rand"]
serde = ["base64", "crypto/serde", "dep:serde", "encoding/serde", "hashes/serde", "internals/serde", "key-expression/serde", "network/serde", "primitives/serde", "secp256k1/serde", "taproot-primitives/serde", "units/serde"]
secp-global-context = ["secp256k1/global-context"]
@@ -26,6 +26,7 @@ secp-recovery = ["secp256k1/recovery"]
arbitrary = ["crypto/arbitrary", "dep:arbitrary", "units/arbitrary", "primitives/arbitrary", "hashes/arbitrary", "key-expression/arbitrary", "secp256k1/arbitrary", "taproot-primitives/arbitrary", "network/arbitrary"]
[dependencies]
+addresses = { package = "bitcoin-addresses", path = "../addresses", version = "0.0.0", default-features = false, features = ["alloc"] }
base58 = { package = "base58ck", path = "../base58", version = "0.4.0", default-features = false, features = ["alloc"] }
bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] }
crypto = { package = "bitcoin-crypto", path = "../crypto", version = "0.2.0", default-features = false, features = ["alloc", "hex"] }
diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs
index be9ff3dd..6aa07881 100644
--- a/bitcoin/src/blockdata/script/mod.rs
+++ b/bitcoin/src/blockdata/script/mod.rs
@@ -52,7 +52,6 @@ mod owned;
mod push_bytes;
#[cfg(test)]
mod tests;
-pub mod witness_program;
pub mod witness_version;
use io::{BufRead, Write};
@@ -73,6 +72,8 @@ pub use self::{
owned::{ScriptBufExt, ScriptPubKeyBufExt, ScriptSigBufExt},
push_bytes::{PushBytes, PushBytesBuf, PushBytesExt, PushBytesErrorReport},
};
+#[doc(inline)]
+pub use addresses::witness_program;
#[doc(no_inline)]
pub use primitives::script::ScriptBufDecoderError;
#[doc(inline)]
diff --git a/bitcoin/src/blockdata/script/witness_program.rs b/bitcoin/src/blockdata/script/witness_program.rs
deleted file mode 100644
index e991aa6d..00000000
--- a/bitcoin/src/blockdata/script/witness_program.rs
+++ /dev/null
@@ -1,232 +0,0 @@
-//! The segregated witness program as defined by [BIP-0141].
-//!
-//! > A scriptPubKey (or redeemScript as defined in BIP-0016/P2SH) that consists of a 1-byte push
-//! > opcode (for 0 to 16) followed by a data push between 2 and 40 bytes gets a new special
-//! > meaning. The value of the first push is called the "version byte". The following byte
-//! > vector pushed is called the "witness program".
-//!
-//! [BIP-0141]: <https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki>
-
-use internals::array_vec::ArrayVec;
-
-use super::witness_version::WitnessVersion;
-use super::{PushBytes, WScriptHash, WitnessScript, WitnessScriptSizeError};
-use crate::crypto::key::{FullPublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
-use crate::script::WitnessScriptExt as _;
-use crate::taproot::TapNodeHash;
-
-#[rustfmt::skip] // Keep public re-exports separate.
-#[doc(no_inline)]
-pub use self::error::Error;
-
-/// The minimum byte size of a segregated witness program.
-pub const MIN_SIZE: usize = 2;
-
-/// The maximum byte size of a segregated witness program.
-pub const MAX_SIZE: usize = 40;
-
-/// The P2A program which is given by 0x4e73.
-pub(crate) const P2A_PROGRAM: [u8; 2] = [78, 115];
-
-/// The segregated witness program.
-///
-/// The segregated witness program is technically only the program bytes _excluding_ the witness
-/// version, however we maintain length invariants on the `program` that are governed by the version
-/// number, therefore we carry the version number around along with the program bytes.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct WitnessProgram {
- /// The SegWit version associated with this witness program.
- version: WitnessVersion,
- /// The witness program (between 2 and 40 bytes).
- program: ArrayVec<u8, MAX_SIZE>,
-}
-
-impl WitnessProgram {
- /// Constructs a new witness program, copying the content from the given byte slice.
- pub fn new(version: WitnessVersion, bytes: &[u8]) -> Result<Self, Error> {
- let program_len = bytes.len();
- if program_len < MIN_SIZE || program_len > MAX_SIZE {
- return Err(Error::InvalidLength(program_len));
- }
-
- // Specific SegWit v0 check. These addresses can never spend funds sent to them.
- if version == WitnessVersion::V0 && (program_len != 20 && program_len != 32) {
- return Err(Error::InvalidSegwitV0Length(program_len));
- }
-
- let program = ArrayVec::from_slice(bytes);
- Ok(Self { version, program })
- }
-
- /// Constructs a new [`WitnessProgram`] from a 20 byte pubkey hash.
- fn new_p2wpkh(program: [u8; 20]) -> Self {
- Self { version: WitnessVersion::V0, program: ArrayVec::from_slice(&program) }
- }
-
- /// Constructs a new [`WitnessProgram`] from a 32 byte script hash.
- fn new_p2wsh(program: [u8; 32]) -> Self {
- Self { version: WitnessVersion::V0, program: ArrayVec::from_slice(&program) }
- }
-
- /// Constructs a new [`WitnessProgram`] from a 32 byte serialized Taproot x-only pubkey.
- fn new_p2tr(program: [u8; 32]) -> Self {
- Self { version: WitnessVersion::V1, program: ArrayVec::from_slice(&program) }
- }
-
- /// Constructs a new [`WitnessProgram`] from `pk` for a P2WPKH output.
- pub fn p2wpkh(pk: FullPublicKey) -> Self {
- let hash = pk.wpubkey_hash();
- Self::new_p2wpkh(hash.to_byte_array())
- }
-
- /// Constructs a new [`WitnessProgram`] from `script` for a P2WSH output.
- pub fn p2wsh(script: &WitnessScript) -> Result<Self, WitnessScriptSizeError> {
- script.wscript_hash().map(Self::p2wsh_from_hash)
- }
-
- /// Constructs a new [`WitnessProgram`] from `script` for a P2WSH output.
- pub fn p2wsh_from_hash(hash: WScriptHash) -> Self { Self::new_p2wsh(hash.to_byte_array()) }
-
- /// Constructs a new [`WitnessProgram`] from an untweaked key for a P2TR output.
- ///
- /// This function applies BIP-0341 key-tweaking to the untweaked
- /// key using the merkle root, if it's present.
- pub fn p2tr<K: Into<UntweakedPublicKey>>(
- internal_key: K,
- merkle_root: Option<TapNodeHash>,
- ) -> Self {
- let internal_key = internal_key.into();
- let output_key = internal_key.tap_tweak(merkle_root);
- let (pubkey, _) = output_key.as_x_only_public_key().serialize();
- Self::new_p2tr(pubkey)
- }
-
- /// Constructs a new [`WitnessProgram`] from a tweaked key for a P2TR output.
- pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Self {
- let (pubkey, _) = output_key.as_x_only_public_key().serialize();
- Self::new_p2tr(pubkey)
- }
-
- /// Constructs a new [`WitnessProgram`] for a P2A output.
- pub const fn p2a() -> Self {
- Self { version: WitnessVersion::V1, program: ArrayVec::from_slice(&P2A_PROGRAM) }
- }
-
- /// Returns the witness program version.
- pub fn version(&self) -> WitnessVersion { self.version }
-
- /// Returns the witness program.
- pub fn program(&self) -> &PushBytes {
- self.program
- .as_slice()
- .try_into()
- .expect("witness programs are always smaller than max size of PushBytes")
- }
-
- /// Returns true if this witness program is for a P2WPKH output.
- pub fn is_p2wpkh(&self) -> bool {
- self.version == WitnessVersion::V0 && self.program.len() == 20
- }
-
- /// Returns true if this witness program is for a P2WSH output.
- pub fn is_p2wsh(&self) -> bool {
- self.version == WitnessVersion::V0 && self.program.len() == 32
- }
-
- /// Returns true if this witness program is for a P2TR output.
- pub fn is_p2tr(&self) -> bool { self.version == WitnessVersion::V1 && self.program.len() == 32 }
-
- /// Returns true if this witness program is for a P2A output.
- pub fn is_p2a(&self) -> bool {
- self.version == WitnessVersion::V1 && self.program == P2A_PROGRAM
- }
-}
-
-/// Error types for witness programs.
-pub mod error {
- use core::convert::Infallible;
- use core::fmt;
-
- /// Witness program error.
- #[derive(Clone, Debug, PartialEq, Eq)]
- #[non_exhaustive]
- pub enum Error {
- /// The witness program must be between 2 and 40 bytes in length.
- InvalidLength(usize),
- /// A v0 witness program must be either of length 20 or 32.
- InvalidSegwitV0Length(usize),
- }
-
- impl From<Infallible> for Error {
- fn from(never: Infallible) -> Self { match never {} }
- }
-
- impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- Self::InvalidLength(len) =>
- write!(f, "witness program must be between 2 and 40 bytes: length={}", len),
- Self::InvalidSegwitV0Length(len) =>
- write!(f, "a v0 witness program must be either 20 or 32 bytes: length={}", len),
- }
- }
- }
-
- #[cfg(feature = "std")]
- impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match self {
- Self::InvalidLength(_) | Self::InvalidSegwitV0Length(_) => None,
- }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn witness_program_is_too_short() {
- let arbitrary_bytes = [0x00; MIN_SIZE - 1];
- assert!(WitnessProgram::new(WitnessVersion::V15, &arbitrary_bytes).is_err()); // Arbitrary version
- }
-
- #[test]
- fn witness_program_is_too_long() {
- let arbitrary_bytes = [0x00; MAX_SIZE + 1];
- assert!(WitnessProgram::new(WitnessVersion::V15, &arbitrary_bytes).is_err()); // Arbitrary version
- }
-
- #[test]
- fn valid_v0_witness_programs() {
- let arbitrary_bytes = [0x00; MAX_SIZE];
-
- for size in MIN_SIZE..=MAX_SIZE {
- let program = WitnessProgram::new(WitnessVersion::V0, &arbitrary_bytes[..size]);
-
- if size == 20 {
- assert!(program.expect("valid witness program").is_p2wpkh());
- continue;
- }
- if size == 32 {
- assert!(program.expect("valid witness program").is_p2wsh());
- continue;
- }
- assert!(program.is_err());
- }
- }
-
- #[test]
- fn valid_v1_witness_programs() {
- let arbitrary_bytes = [0x00; 32];
- assert!(WitnessProgram::new(WitnessVersion::V1, &arbitrary_bytes)
- .expect("valid witness program")
- .is_p2tr());
-
- let p2a_bytes = [78, 115];
- assert!(WitnessProgram::new(WitnessVersion::V1, &p2a_bytes)
- .expect("valid witness program")
- .is_p2a());
- }
-}
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index 65b7910e..60025049 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -62,6 +62,7 @@ extern crate std;
#[cfg(feature = "arbitrary")]
pub extern crate arbitrary;
+pub extern crate addresses;
pub extern crate base58;
#[cfg(feature = "base64")]
pub extern crate base64;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.