Repository: rust-bitcoin/rust-bitcoin
Pull request #2795 (2024-05-23 02:48:43)

Make `Address:p2sh_from_hash` public
We previously made this function Private and added a comment that doing so was somehow better to remove the footgun of hashing the wrong length script. However in hindsight this was a bad idea and users want the functionality.
    
Make the `Address:p2sh_from_hash` public and document it as we do for `Address::p2sh`.

This is an additive change and is expected to be backported to `v0.32`, as part of the fix to #2784. Please note it introduces the footgun that is described in the function rustdoc. This will be improved as a separate patch and added to the current release.

tcharding: Just changed the commit log for the last patch, we are going to end up with millions of commits that all just run `just check-api` and commit the changes to the `api/` files. Since I just mentioned to @jamillambert that typically we do not want to use the same commit message in multiple places too much I thought I'd mention it.

Are you ok with me using `git commit -a -m 'api: Run just check-api'` for all of these patches @apoelstra?
tcharding: @sanket1729! Thanks for the review man.

Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c12380e3..69156b0b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -136,7 +136,7 @@ grammar fixes.
 
 Pull request merge requirements:
 - all CI test should pass,
-- at least one "accepts"/ACKs from the repository maintainers
+- at least two "accepts"/ACKs from the repository maintainers (see "refactor carve-out").
 - no reasonable "rejects"/NACKs from anybody who reviewed the code.
 
 Current list of the project maintainers:
@@ -150,6 +150,38 @@ Current list of the project maintainers:
 - [Riccardo Casatta](https://github.com/RCasatta)
 - [Tobin Harding](https://github.com/tcharding)
 
+#### One ACK carve-out
+
+The repository is going through heavy refactoring and "trivial" API redesign
+(eg, rename `Foo::empty` to `Foo::new`) as we push towards API stabilization. As
+such reviewers are either bored or overloaded with notifications, hence we have
+created a carve out to the 2-ACK rule.
+
+We reserve the right to merge PRs with a single ACK [0], at any time, if they match
+any of the following conditions:
+
+0. PR has a single ACK and has sat open for at least two weeks with no comments,
+   questions, or NACKs.
+1. PR only touches CI i.e, only changes any of the test scripts and/or
+   stuff in `.github/workflows`.
+2. Non-content changing documentation fixes i.e., grammar/typos, spelling, full
+   stops, capital letters. Any change with more substance must still get two
+   ACKs.
+3. Code moves that do not change the API e.g., moving error types to a private
+   submodule and re-exporting them from the original module. Must not include
+   any code changes except to import paths. Requires absolutely no change to the
+   public API.
+4. PR has previously had two ACKs, had minimal changes, and gets a single ACK
+   from Andrew. This call is subjective, gives extra privileges, but also
+   requires extra responsibility/accountability (including running a bunch
+   of local CI checks before merging) [1].
+
+
+
+[0] - Obviously author and ACK'er must not be the same person.
+[1] - The aim is to reduce the burden of re-ACK'ing trivial changes and also
+      alleviate the problem of devs spread around the world in different timezones.
+
 #### Backporting
 
 We maintain release branches (e.g. `0.32.x` for the `v0.32` releases).
diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock
index f30294e9..cbc17e22 100644
--- a/Cargo-minimal.lock
+++ b/Cargo-minimal.lock
@@ -47,7 +47,7 @@ dependencies = [
 
 [[package]]
 name = "bitcoin"
-version = "0.32.0-rc1"
+version = "0.33.0-unreleased"
 dependencies = [
  "base58ck",
  "base64",
diff --git a/Cargo-recent.lock b/Cargo-recent.lock
index 57490f67..2bd141b0 100644
--- a/Cargo-recent.lock
+++ b/Cargo-recent.lock
@@ -46,7 +46,7 @@ dependencies = [
 
 [[package]]
 name = "bitcoin"
-version = "0.32.0-rc1"
+version = "0.33.0-unreleased"
 dependencies = [
  "base58ck",
  "base64",
diff --git a/api/bitcoin/all-features.txt b/api/bitcoin/all-features.txt
index 31b4d1e6..7cc7e30f 100644
--- a/api/bitcoin/all-features.txt
+++ b/api/bitcoin/all-features.txt
@@ -7119,6 +7119,7 @@ pub fn bitcoin::address::Address::is_spend_standard(&self) -> bool
 pub fn bitcoin::address::Address::matches_script_pubkey(&self, script: &bitcoin::blockdata::script::Script) -> bool
 pub fn bitcoin::address::Address::p2pkh(pk: impl core::convert::Into<bitcoin::PubkeyHash>, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2sh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> core::result::Result<bitcoin::address::Address, bitcoin::address::error::P2shError>
+pub fn bitcoin::address::Address::p2sh_from_hash(hash: bitcoin::blockdata::script::ScriptHash, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwpkh(pk: &bitcoin::CompressedPublicKey, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwsh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2tr<C: secp256k1::context::Verification>(secp: &secp256k1::Secp256k1<C>, internal_key: bitcoin::key::UntweakedPublicKey, merkle_root: core::option::Option<bitcoin::taproot::TapNodeHash>, hrp: impl core::convert::Into<bitcoin::address::KnownHrp>) -> bitcoin::address::Address
@@ -7129,7 +7130,6 @@ pub fn bitcoin::address::Address::pubkey_hash(&self) -> core::option::Option<bit
 pub fn bitcoin::address::Address::script_hash(&self) -> core::option::Option<bitcoin::blockdata::script::ScriptHash>
 pub fn bitcoin::address::Address::script_pubkey(&self) -> bitcoin::blockdata::script::ScriptBuf
 pub fn bitcoin::address::Address::to_qr_uri(&self) -> alloc::string::String
-pub fn bitcoin::address::Address::witness_program(&self) -> core::option::Option<bitcoin::blockdata::script::witness_program::WitnessProgram>
 pub fn bitcoin::address::Address<N>::serialize<S>(&self, serializer: S) -> core::result::Result<<S as serde::ser::Serializer>::Ok, <S as serde::ser::Serializer>::Error> where S: serde::ser::Serializer
 pub fn bitcoin::address::Address<V>::as_unchecked(&self) -> &bitcoin::address::Address<bitcoin::address::NetworkUnchecked>
 pub fn bitcoin::address::Address<V>::clone(&self) -> bitcoin::address::Address<V>
diff --git a/api/bitcoin/default-features.txt b/api/bitcoin/default-features.txt
index 5e7768fb..152f5460 100644
--- a/api/bitcoin/default-features.txt
+++ b/api/bitcoin/default-features.txt
@@ -6787,6 +6787,7 @@ pub fn bitcoin::address::Address::is_spend_standard(&self) -> bool
 pub fn bitcoin::address::Address::matches_script_pubkey(&self, script: &bitcoin::blockdata::script::Script) -> bool
 pub fn bitcoin::address::Address::p2pkh(pk: impl core::convert::Into<bitcoin::PubkeyHash>, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2sh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> core::result::Result<bitcoin::address::Address, bitcoin::address::error::P2shError>
+pub fn bitcoin::address::Address::p2sh_from_hash(hash: bitcoin::blockdata::script::ScriptHash, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwpkh(pk: &bitcoin::CompressedPublicKey, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwsh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2tr<C: secp256k1::context::Verification>(secp: &secp256k1::Secp256k1<C>, internal_key: bitcoin::key::UntweakedPublicKey, merkle_root: core::option::Option<bitcoin::taproot::TapNodeHash>, hrp: impl core::convert::Into<bitcoin::address::KnownHrp>) -> bitcoin::address::Address
@@ -6797,7 +6798,6 @@ pub fn bitcoin::address::Address::pubkey_hash(&self) -> core::option::Option<bit
 pub fn bitcoin::address::Address::script_hash(&self) -> core::option::Option<bitcoin::blockdata::script::ScriptHash>
 pub fn bitcoin::address::Address::script_pubkey(&self) -> bitcoin::blockdata::script::ScriptBuf
 pub fn bitcoin::address::Address::to_qr_uri(&self) -> alloc::string::String
-pub fn bitcoin::address::Address::witness_program(&self) -> core::option::Option<bitcoin::blockdata::script::witness_program::WitnessProgram>
 pub fn bitcoin::address::Address<V>::as_unchecked(&self) -> &bitcoin::address::Address<bitcoin::address::NetworkUnchecked>
 pub fn bitcoin::address::Address<V>::clone(&self) -> bitcoin::address::Address<V>
 pub fn bitcoin::address::Address<V>::cmp(&self, other: &bitcoin::address::Address<V>) -> core::cmp::Ordering
diff --git a/api/bitcoin/no-features.txt b/api/bitcoin/no-features.txt
index 6ed16407..d9fe7269 100644
--- a/api/bitcoin/no-features.txt
+++ b/api/bitcoin/no-features.txt
@@ -6154,6 +6154,7 @@ pub fn bitcoin::address::Address::is_spend_standard(&self) -> bool
 pub fn bitcoin::address::Address::matches_script_pubkey(&self, script: &bitcoin::blockdata::script::Script) -> bool
 pub fn bitcoin::address::Address::p2pkh(pk: impl core::convert::Into<bitcoin::PubkeyHash>, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2sh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> core::result::Result<bitcoin::address::Address, bitcoin::address::error::P2shError>
+pub fn bitcoin::address::Address::p2sh_from_hash(hash: bitcoin::blockdata::script::ScriptHash, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwpkh(pk: &bitcoin::CompressedPublicKey, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2shwsh(script: &bitcoin::blockdata::script::Script, network: impl core::convert::Into<bitcoin::network::NetworkKind>) -> bitcoin::address::Address
 pub fn bitcoin::address::Address::p2tr<C: secp256k1::context::Verification>(secp: &secp256k1::Secp256k1<C>, internal_key: bitcoin::key::UntweakedPublicKey, merkle_root: core::option::Option<bitcoin::taproot::TapNodeHash>, hrp: impl core::convert::Into<bitcoin::address::KnownHrp>) -> bitcoin::address::Address
@@ -6164,7 +6165,6 @@ pub fn bitcoin::address::Address::pubkey_hash(&self) -> core::option::Option<bit
 pub fn bitcoin::address::Address::script_hash(&self) -> core::option::Option<bitcoin::blockdata::script::ScriptHash>
 pub fn bitcoin::address::Address::script_pubkey(&self) -> bitcoin::blockdata::script::ScriptBuf
 pub fn bitcoin::address::Address::to_qr_uri(&self) -> alloc::string::String
-pub fn bitcoin::address::Address::witness_program(&self) -> core::option::Option<bitcoin::blockdata::script::witness_program::WitnessProgram>
 pub fn bitcoin::address::Address<V>::as_unchecked(&self) -> &bitcoin::address::Address<bitcoin::address::NetworkUnchecked>
 pub fn bitcoin::address::Address<V>::clone(&self) -> bitcoin::address::Address<V>
 pub fn bitcoin::address::Address<V>::cmp(&self, other: &bitcoin::address::Address<V>) -> core::cmp::Ordering
diff --git a/base58/Cargo.toml b/base58/Cargo.toml
index 681fb032..61fe35a0 100644
--- a/base58/Cargo.toml
+++ b/base58/Cargo.toml
@@ -26,6 +26,3 @@ internals = { package = "bitcoin-internals", version = "0.3.0", features = ["all
 
 [dev-dependencies]
 hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] }
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(fuzzing)', 'cfg(kani)' ] }
diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml
index a09431fb..1f02b287 100644
--- a/bitcoin/Cargo.toml
+++ b/bitcoin/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "bitcoin"
-version = "0.32.0-rc1"
+version = "0.33.0-unreleased"
 authors = ["Andrew Poelstra <apoelstra@wpsoftware.net>"]
 license = "CC0-1.0"
 repository = "https://github.com/rust-bitcoin/rust-bitcoin/"
@@ -32,6 +32,7 @@ base58 = { package = "base58ck", version = "0.1.0", default-features = false }
 bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] }
 hashes = { package = "bitcoin_hashes", version = "0.14.0", default-features = false, features = ["alloc", "io"] }
 hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] }
+hex_lit = "0.1.1"
 internals = { package = "bitcoin-internals", version = "0.3.0", features = ["alloc"] }
 io = { package = "bitcoin-io", version = "0.1.1", default-features = false, features = ["alloc"] }
 secp256k1 = { version = "0.29.0", default-features = false, features = ["hashes", "alloc"] }
@@ -49,7 +50,6 @@ actual-serde = { package = "serde", version = "1.0.103", default-features = fals
 serde_json = "1.0.0"
 serde_test = "1.0.19"
 bincode = "1.3.1"
-hex_lit = "0.1.1"
 
 [target.'cfg(mutate)'.dev-dependencies]
 mutagen = { git = "https://github.com/llogiq/mutagen" }
@@ -79,6 +79,3 @@ required-features = ["std", "rand-std", "bitcoinconsensus"]
 
 [[example]]
 name = "sighash"
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(fuzzing)', 'cfg(kani)', 'cfg(mutate)', 'cfg(rust_v_1_60)'] }
diff --git a/bitcoin/examples/sighash.rs b/bitcoin/examples/sighash.rs
index d90d3954..830fe49b 100644
--- a/bitcoin/examples/sighash.rs
+++ b/bitcoin/examples/sighash.rs
@@ -13,7 +13,7 @@
 
 /// Computes segwit sighash for a transaction input that spends a p2wpkh output with "witness_v0_keyhash" scriptPubKey.type
 ///
-/// # Parameters
+/// # Arguments
 ///
 /// * `raw_tx` - spending tx hex
 /// * `inp_idx` - spending tx input index
@@ -52,7 +52,7 @@ fn compute_sighash_p2wpkh(raw_tx: &[u8], inp_idx: usize, value: u64) {
 
 /// Computes sighash for a legacy multisig transaction input that spends either a p2sh or a p2ms output.
 ///
-/// # Parameters
+/// # Arguments
 ///
 /// * `raw_tx` - spending tx hex
 /// * `inp_idx` - spending tx input inde
@@ -98,7 +98,7 @@ fn compute_sighash_legacy(raw_tx: &[u8], inp_idx: usize, script_pubkey_bytes_opt
 
 /// Computes sighash for a segwit multisig transaction input that spends a p2wsh output with "witness_v0_scripthash" scriptPubKey.type
 ///
-/// # Parameters
+/// # Arguments
 ///
 /// * `raw_tx` - spending tx hex
 /// * `inp_idx` - spending tx input index
diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs
index c2cdb9cc..3883378f 100644
--- a/bitcoin/src/address/mod.rs
+++ b/bitcoin/src/address/mod.rs
@@ -384,8 +384,13 @@ pub fn p2sh(script: &Script, network: impl Into<NetworkKind>) -> Result<Address,
         Ok(Address::p2sh_from_hash(hash, network))
     }
 
-    // This is intentionally not public so we enforce script length checks.
-    fn p2sh_from_hash(hash: ScriptHash, network: impl Into<NetworkKind>) -> Address {
+    /// Creates a pay to script hash P2SH address from a script hash.
+    ///
+    /// # Warning
+    ///
+    /// 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<NetworkKind>) -> Address {
         Self(AddressInner::P2sh { hash, network: network.into() }, PhantomData)
     }
 
@@ -490,16 +495,6 @@ pub fn script_hash(&self) -> Option<ScriptHash> {
         }
     }
 
-    /// Gets the witness program for this address if this is a segwit address.
-    pub fn witness_program(&self) -> Option<WitnessProgram> {
-        use AddressInner::*;
-
-        match self.0 {
-            Segwit { ref program, hrp: _ } => Some(*program),
-            _ => None,
-        }
-    }
-
     /// Checks whether or not the address is following Bitcoin standardness rules when
     /// *spending* from this address. *NOT* to be called by senders.
     ///
diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs
index 9c8dc58e..238af1f1 100644
--- a/bitcoin/src/blockdata/constants.rs
+++ b/bitcoin/src/blockdata/constants.rs
@@ -7,6 +7,7 @@
 //! single transaction.
 
 use hashes::{sha256d, Hash};
+use hex_lit::hex;
 use internals::impl_array_newtype;
 
 use crate::blockdata::block::{self, Block};
@@ -49,23 +50,6 @@
 /// Number of blocks needed for an output from a coinbase transaction to be spendable.
 pub const COINBASE_MATURITY: u32 = 100;
 
-// This is the 65 byte (uncompressed) pubkey used as the one-and-only output of the genesis transaction.
-//
-// ref: https://blockstream.info/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b?expand
-// Note output script includes a leading 0x41 and trailing 0xac (added below using the `script::Builder`).
-#[rustfmt::skip]
-const GENESIS_OUTPUT_PK: [u8; 65] = [
-    0x04,
-    0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27,
-    0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10,
-    0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
-    0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6,
-    0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4,
-    0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde,
-    0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57,
-    0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f
-];
-
 /// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block.
 fn bitcoin_genesis_tx() -> Transaction {
     // Base
@@ -90,8 +74,9 @@ fn bitcoin_genesis_tx() -> Transaction {
     });
 
     // Outputs
+    let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
     let out_script =
-        script::Builder::new().push_slice(GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script();
+        script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script();
     ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script });
 
     // end
diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs
index 0de951c7..cdf796f4 100644
--- a/bitcoin/src/blockdata/transaction.rs
+++ b/bitcoin/src/blockdata/transaction.rs
@@ -1303,7 +1303,7 @@ fn from(tx: &Transaction) -> Wtxid { tx.compute_wtxid() }
 /// a [`TxOut`] when adding another [`TxOut`] to the transaction.  This happens when the new
 /// [`TxOut`] added causes the output length `VarInt` to increase its encoding length.
 ///
-/// # Parameters
+/// # Arguments
 ///
 /// * `fee_rate` - the fee rate of the transaction being created.
 /// * `satisfaction_weight` - satisfied spending conditions weight.
@@ -1322,7 +1322,7 @@ pub fn effective_value(
 /// This function computes the weight of a transaction which is not fully known. All that is needed
 /// is the lengths of scripts and witness elements.
 ///
-/// # Parameters
+/// # Arguments
 ///
 /// * `inputs` - an iterator which returns `InputWeightPrediction` for each input of the
 ///   to-be-constructed transaction.
@@ -2463,7 +2463,7 @@ fn outpoint_format() {
 
 #[cfg(bench)]
 mod benches {
-    use hex::test_hex_unwrap as hex;
+    use hex_lit::hex;
     use io::sink;
     use test::{black_box, Bencher};
 
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index 951d62b7..5d8abc6a 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -1521,12 +1521,12 @@ fn private_key_debug_is_obfuscated() {
     }
 
     #[test]
-    #[cfg(not(feature = "std"))]
+    #[cfg(all(not(feature = "std"), feature = "no-std"))]
     fn private_key_debug_is_obfuscated() {
         let sk =
             PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
         // Why is this not shortened? In rust-secp256k1/src/secret it is printed with "#{:016x}"?
-        let want = "PrivateKey { compressed: true, network: Test, inner: SecretKey(#7217ac58fbad8880a91032107b82cb6c5422544b426c350ee005cf509f3dbf7b) }";
+        let want = "PrivateKey { compressed: true, network: Testnet, inner: SecretKey(#7217ac58fbad8880a91032107b82cb6c5422544b426c350ee005cf509f3dbf7b) }";
         let got = format!("{:?}", sk);
         assert_eq!(got, want)
     }
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index f76d6189..3f162df7 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -88,6 +88,3 @@ path = "fuzz_targets/hashes/sha512.rs"
 [[bin]]
 name = "units_deserialize_amount"
 path = "fuzz_targets/units/deserialize_amount.rs"
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(fuzzing)'] }
diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml
index 1368c8ee..6538379b 100644
--- a/hashes/Cargo.toml
+++ b/hashes/Cargo.toml
@@ -36,6 +36,3 @@ serde = { version = "1.0", default-features = false, optional = true }
 [dev-dependencies]
 serde_test = "1.0"
 serde_json = "1.0"
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(hashes_fuzz)', 'cfg(rust_v_1_64)' ] }
diff --git a/internals/Cargo.toml b/internals/Cargo.toml
index 9f8f3d5e..ca6d81be 100644
--- a/internals/Cargo.toml
+++ b/internals/Cargo.toml
@@ -26,6 +26,3 @@ rustdoc-args = ["--cfg", "docsrs"]
 serde = { version = "1.0.103", default-features = false, optional = true }
 
 [dev-dependencies]
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(rust_v_1_64)', 'cfg(rust_v_1_61)'] }
diff --git a/internals/src/error/parse_error.rs b/internals/src/error/parse_error.rs
index 2b032505..7f8903dd 100644
--- a/internals/src/error/parse_error.rs
+++ b/internals/src/error/parse_error.rs
@@ -9,7 +9,7 @@
 /// The resulting type is public, conditionally implements `std::error::Error` and has a private
 /// `new()` method for convenience.
 ///
-/// # Parameters
+/// ## Parameters
 ///
 /// * `name` - the name of the error type
 /// * `source` - the type of the source type
diff --git a/io/Cargo.toml b/io/Cargo.toml
index 3369d1f9..ce3a71a4 100644
--- a/io/Cargo.toml
+++ b/io/Cargo.toml
@@ -21,6 +21,3 @@ alloc = []
 [package.metadata.docs.rs]
 all-features = true
 rustdoc-args = ["--cfg", "docsrs"]
-
-[lints.rust]
-unexpected_cfgs = { level = "deny" }
diff --git a/nightly-version b/nightly-version
index 3cd76cdc..e70649f1 100644
--- a/nightly-version
+++ b/nightly-version
@@ -1,1 +1,1 @@
-nightly-2024-05-21
+nightly-2024-05-04
diff --git a/units/Cargo.toml b/units/Cargo.toml
index afb1ab1a..04fffb94 100644
--- a/units/Cargo.toml
+++ b/units/Cargo.toml
@@ -29,6 +29,3 @@ serde = { version = "1.0.103", default-features = false, features = ["derive"],
 [dev-dependencies]
 serde_test = "1.0"
 serde_json = "1.0"
-
-[lints.rust]
-unexpected_cfgs = { level = "deny", check-cfg = ['cfg(kani)'] }


Test patch:
diff --git a/hashes/tests/regression.rs b/hashes/tests/regression.rs
deleted file mode 100644
index eba7f308..00000000
--- a/hashes/tests/regression.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-//! Regression tests for each hash type.
-
-use bitcoin_hashes::{
-    hash160, ripemd160, sha1, sha256, sha256d, sha256t, sha384, sha512, sha512_256, siphash24,
-    Hash as _, Hmac, HmacEngine, HashEngine as _,
-};
-
-const DATA: &str = "arbitrary data to hash as a regression test";
-const HMAC_KEY: &[u8] = b"some key";
-
-macro_rules! impl_regression_test {
-    ($($test_name:ident, $module:ident, $want:literal);* $(;)?) => {
-        $(
-            #[test]
-            fn $test_name() {
-                let hash = $module::Hash::hash(DATA.as_bytes());
-                let got = format!("{}", hash);
-                assert_eq!(got, $want);
-            }
-        )*
-    }
-}
-
-impl_regression_test! {
-    regression_hash160, hash160, "a17909f6d5373b0085c4180ba207126e5040f74d";
-    regression_ripemd160, ripemd160, "e6801701c77a1cd85662335258c7869631b4a9a8";
-    regression_sha1, sha1, "e1e81eeabadafa3d5d41cc3f405385426b0f47fd";
-    regression_sha256, sha256, "d291c6c5a07fa1d9315cdae090ebe14169fbe0a219cd55a48d0d2104eab6ec51";
-    regression_sha256d, sha256d, "93a743b022290bde3233a619b21aaebe06c5cf5cc959464c41be35711e37731b";
-    regression_sha384, sha384, "f545bd83d297978d47a7f26b858a54188499dfb4d7d570a6a2362c765031d57a29d7e002df5e34d184e70b65a4f47153";
-    regression_sha512, sha512, "057d0a37e9e0ac9a93acde0752748da059a27bcf946c7af00692ac1a95db8d21f965f40af22efc4710f100f8d3e43f79f77b1f48e1e400a95b7344b7bc0dfd10";
-    regression_sha512_256, sha512_256, "e204244c429b5bca037a2a8a6e7ed8a42b808ceaff182560840bb8c5c8e9a2ec";
-    regression_siphash24, siphash24, "e823ed82311d601a";
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
-pub struct RegHashTag;
-
-impl sha256t::Tag for RegHashTag {
-    fn engine() -> sha256::HashEngine {
-        let midstate = sha256::Midstate::from_byte_array([0xab; 32]);
-        sha256::HashEngine::from_midstate(midstate, 64)
-    }
-}
-
-type RegHash = sha256t::Hash<RegHashTag>;
-
-#[test]
-fn regression_sha256t() {
-    let hash = RegHash::hash(DATA.as_bytes());
-    let got = format!("{}", hash);
-    let want = "17db326d7c13867376ccca1f8a211377be3cbeaeb372f167822284866ddf14ca";
-    assert_eq!(got, want);
-}
-
-#[test]
-fn regression_hmac_sha256_with_default_key() {
-    let hash = Hmac::<sha256::Hash>::hash(DATA.as_bytes());
-    let got = format!("{}", hash);
-    let want = "58cc7ed8567bd86eba61f7ed2d5a4edab1774dc10488e57de2eb007a2d9ae82d";
-    assert_eq!(got, want);
-}
-
-#[test]
-fn regression_hmac_sha512_with_default_key() {
-    let hash = Hmac::<sha512::Hash>::hash(DATA.as_bytes());
-    let got = format!("{}", hash);
-    let want = "5f5db2f3e1178bf19af5db38a0ed04dc5bc52d641648542886eea9b6bbec0db658ed7a5799ca18f5bc1949f39d24151a32990ee85974e40bb8a35e2288f494ce";
-    assert_eq!(got, want);
-}
-
-#[test]
-fn regression_hmac_sha256_with_key() {
-    let mut engine = HmacEngine::<sha256::Hash>::new(HMAC_KEY);
-    engine.input(DATA.as_bytes());
-    let hash = Hmac::from_engine(engine);
-
-    let got = format!("{}", hash);
-    let want = "d159cecaf4adf90b6a641bab767e4817d3a51c414acea3682686c35ec0b37b52";
-    assert_eq!(got, want);
-}
-
-#[test]
-fn regression_hmac_sha512_with_key() {
-    let mut engine = HmacEngine::<sha512::Hash>::new(HMAC_KEY);
-    engine.input(DATA.as_bytes());
-    let hash = Hmac::from_engine(engine);
-
-    let got = format!("{}", hash);
-    let want = "8511773748f89ba22c07fb3a2981a12c1823695119de41f4a62aead6b848bd34939acf16475c35ed7956114fead3e794cc162ecd35e447a4dabc3227d55f757b";
-    assert_eq!(got, want);
-}