What changed, and why it matters
This commit removes a redundant feature flag called 'rand-std' from the rust-bitcoin library and replaces its use with the combination of 'rand' and 'std'. It is a cleanup change to make feature selection clearer for users. There is no security vulnerability or bug fix in the code itself.
No security action required. Users who previously enabled 'rand-std' should update their Cargo.toml to use 'rand' and 'std' instead when upgrading.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit drops the ‘rand-std’ Cargo feature, which previously enabled both ‘secp256k1/rand’ and ‘std’. It replaces all references to ‘rand-std’ with the explicit pair ‘rand’ + ‘std’. This affects conditional compilation (cfg) gates, example required-features, test scripts, and documentation. The functional behavior of the code is unchanged; only the feature-gating surface is simplified.
Changed components
bitcoin/Cargo.toml feature definitionsbitcoin/src/address/mod.rs documentation cfgbitcoin/src/consensus/encode.rs test cfgbitcoin/src/crypto/key.rs re-exports and method cfgbitcoin/src/lib.rs feature documentationbitcoin/src/merkle_tree/block.rs test cfgbitcoin/src/psbt/mod.rs signing cfg and testsbitcoin/src/sign_message.rs test cfgbitcoin/tests/psbt-sign-taproot.rs test cfgbitcoin/contrib/test_vars.sh CI feature listsbitcoin/CHANGELOG.md release notesInspect captured patch +36 / −35
diff --git a/bitcoin/CHANGELOG.md b/bitcoin/CHANGELOG.md
index a1523f7f..fcc751b3 100644
--- a/bitcoin/CHANGELOG.md
+++ b/bitcoin/CHANGELOG.md
@@ -3,6 +3,7 @@
- TODO: Make a comment about `Amount::MAX_MONEY` (perhaps here in `bitcoin` release notes as well as in `amount`)
- Use MAX_MONEY in serde regression test [#3950](https://github.com/rust-bitcoin/rust-bitcoin/pull/3950)
+- Remove rand-std feature. Just use rand (but you probably need std enabled as well). [#5293](https://github.com/rust-bitcoin/rust-bitcoin/pull/5293)
## Breaking changes
diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml
index 1f00feb4..79f2c2f8 100644
--- a/bitcoin/Cargo.toml
+++ b/bitcoin/Cargo.toml
@@ -17,7 +17,6 @@ exclude = ["tests", "contrib"]
[features]
default = [ "std", "secp-recovery" ]
std = ["base58/std", "bech32/std", "hashes/std", "hex/std", "internals/std", "io/std", "primitives/std", "secp256k1/std", "units/std", "base64?/std", "bitcoinconsensus?/std"]
-rand-std = ["secp256k1/rand", "std"]
rand = ["secp256k1/rand"]
serde = ["base64", "dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"]
secp-global-context = ["secp256k1/global-context"]
@@ -62,27 +61,27 @@ required-features = ["std", "bitcoinconsensus"]
[[example]]
name = "ecdsa-psbt-simple"
-required-features = ["rand-std"]
+required-features = ["rand", "std"]
[[example]]
name = "create-p2wpkh-address"
-required-features = ["rand-std"]
+required-features = ["rand", "std"]
[[example]]
name = "sign-tx-segwit-v0"
-required-features = ["rand-std"]
+required-features = ["rand", "std"]
[[example]]
name = "sign-tx-taproot"
-required-features = ["rand-std"]
+required-features = ["rand", "std"]
[[example]]
name = "taproot-psbt"
-required-features = ["rand-std", "bitcoinconsensus"]
+required-features = ["rand", "std", "bitcoinconsensus"]
[[example]]
name = "taproot-psbt-simple"
-required-features = ["rand-std"]
+required-features = ["rand", "std"]
[[example]]
name = "sighash"
diff --git a/bitcoin/contrib/test_vars.sh b/bitcoin/contrib/test_vars.sh
index 0e566596..6b2d09e8 100644
--- a/bitcoin/contrib/test_vars.sh
+++ b/bitcoin/contrib/test_vars.sh
@@ -5,10 +5,10 @@
# shellcheck disable=SC2034
# Test all these features with "std" enabled.
-FEATURES_WITH_STD="rand-std serde secp-recovery bitcoinconsensus base64 arbitrary"
+FEATURES_WITH_STD="rand serde secp-recovery bitcoinconsensus base64 arbitrary"
# Test all these features without "std" or "alloc" enabled.
FEATURES_WITHOUT_STD="rand serde secp-recovery bitcoinconsensus base64 arbitrary"
# Run these examples.
-EXAMPLES="ecdsa-psbt:std,bitcoinconsensus sign-tx-segwit-v0:rand-std sign-tx-taproot:rand-std taproot-psbt:bitcoinconsensus,rand-std sighash:std serde:std,serde"
+EXAMPLES="ecdsa-psbt:std,bitcoinconsensus sign-tx-segwit-v0:rand,std sign-tx-taproot:rand,std taproot-psbt:bitcoinconsensus,rand,std sighash:std serde:std,serde"
diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs
index 1154c78c..8197df2f 100644
--- a/bitcoin/src/address/mod.rs
+++ b/bitcoin/src/address/mod.rs
@@ -9,7 +9,7 @@
//! ### Creating a new address from a randomly-generated key pair.
//!
//! ```rust
-//! #[cfg(feature = "rand-std")] {
+//! #[cfg(all(feature = "rand", feature = "std"))] {
//! use bitcoin::secp256k1::rand;
//! use bitcoin::{Address, Network, PublicKey};
//!
diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs
index ff669c7f..ebba899d 100644
--- a/bitcoin/src/consensus/encode.rs
+++ b/bitcoin/src/consensus/encode.rs
@@ -986,7 +986,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn serialization_round_trips() {
use secp256k1::rand::{self, Rng};
diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs
index e0ce609c..4a85cf4d 100644
--- a/bitcoin/src/crypto/key.rs
+++ b/bitcoin/src/crypto/key.rs
@@ -26,7 +26,7 @@ use crate::taproot::{TapNodeHash, TapTweakHash};
#[rustfmt::skip] // Keep public re-exports separate.
pub use secp256k1::{constants, Keypair, Parity, Verification};
-#[cfg(feature = "rand-std")]
+#[cfg(all(feature = "rand", feature = "std"))]
pub use secp256k1::rand;
pub use serialized_x_only::SerializedXOnlyPublicKey;
@@ -538,7 +538,7 @@ pub struct PrivateKey {
impl PrivateKey {
/// Constructs a new compressed ECDSA private key using the secp256k1 algorithm and
/// a secure random number generator.
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
pub fn generate(network: impl Into<NetworkKind>) -> Self {
let secret_key = secp256k1::SecretKey::new(&mut rand::rng());
Self::new(secret_key, network.into())
@@ -866,7 +866,7 @@ pub type UntweakedKeypair = Keypair;
/// # Examples
///
/// ```
-/// # #[cfg(feature = "rand-std")] {
+/// # #[cfg(all(feature = "rand", feature = "std"))] {
/// # use bitcoin::key::{Keypair, TweakedKeypair, TweakedPublicKey};
/// # use bitcoin::secp256k1::rand;
/// # let keypair = TweakedKeypair::dangerous_assume_tweaked(Keypair::new(&mut rand::rng()));
@@ -1730,7 +1730,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn public_key_constructors() {
use secp256k1::rand;
diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs
index c1565833..15e3c401 100644
--- a/bitcoin/src/lib.rs
+++ b/bitcoin/src/lib.rs
@@ -17,7 +17,6 @@
//! * `bitcoinconsensus` (dependency) - enables validating scripts and transactions.
//! * `default` - enables `std` and `secp-recovery`.
//! * `rand` (transitive dependency) - makes it more convenient to generate random values.
-//! * `rand-std` - same as `rand` but also enables `std` here and in `secp256k1`.
//! * `serde` (dependency) - implements `serde`-based serialization and deserialization.
//! * `secp-lowmemory` - optimizations for low-memory devices.
//! * `secp-recovery` - enables calculating public key from a signature and message.
diff --git a/bitcoin/src/merkle_tree/block.rs b/bitcoin/src/merkle_tree/block.rs
index 4b6edc1c..19ec8ff7 100644
--- a/bitcoin/src/merkle_tree/block.rs
+++ b/bitcoin/src/merkle_tree/block.rs
@@ -534,7 +534,7 @@ impl<'a> Arbitrary<'a> for MerkleBlock {
mod tests {
use hex::{DisplayHex, FromHex};
use hex_lit::hex;
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
use {core::cmp, secp256k1::rand::prelude::*};
use super::*;
@@ -542,7 +542,7 @@ mod tests {
use crate::consensus::encode;
use crate::Txid;
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
macro_rules! pmt_tests {
($($name:ident),* $(,)?) => {
$(
@@ -554,7 +554,7 @@ mod tests {
}
}
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
pmt_tests!(
pmt_test_1,
pmt_test_4,
@@ -571,10 +571,10 @@ mod tests {
);
/// Parses the transaction count out of `name` with form: `pmt_test_$num`.
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn pmt_test_from_name(name: &str) { pmt_test(name[9..].parse().unwrap()) }
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn pmt_test(tx_count: usize) {
let mut rng = secp256k1::rand::rng();
// Create some fake tx ids
@@ -744,7 +744,7 @@ mod tests {
assert_eq!(index.len(), 0);
}
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
impl PartialMerkleTree {
/// Flip one bit in one of the hashes - this should break the authentication
fn damage(&mut self, rng: &mut ThreadRng) {
diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs
index faf9f35b..e5e53d95 100644
--- a/bitcoin/src/psbt/mod.rs
+++ b/bitcoin/src/psbt/mod.rs
@@ -438,9 +438,9 @@ impl Psbt {
.tap_tweak(input.tap_merkle_root)
.to_keypair();
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair);
- #[cfg(not(feature = "rand-std"))]
+ #[cfg(not(all(feature = "rand", feature = "std")))]
let signature =
secp256k1::schnorr::sign_no_aux_rand(&sighash.to_byte_array(), &key_pair);
@@ -466,9 +466,9 @@ impl Psbt {
let (sighash, sighash_type) =
self.sighash_taproot(input_index, cache, Some(lh))?;
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
let signature = secp256k1::schnorr::sign(&sighash.to_byte_array(), &key_pair);
- #[cfg(not(feature = "rand-std"))]
+ #[cfg(not(all(feature = "rand", feature = "std")))]
let signature =
secp256k1::schnorr::sign_no_aux_rand(&sighash.to_byte_array(), &key_pair);
@@ -1322,7 +1322,7 @@ mod tests {
use hashes::{hash160, ripemd160, sha256};
use hex::FromHex;
use hex_lit::hex;
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
use {
crate::bip32::Fingerprint,
crate::locktime,
@@ -2355,7 +2355,7 @@ mod tests {
));
}
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn gen_keys() -> (PrivateKey, PublicKey) {
use secp256k1::rand;
@@ -2367,7 +2367,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn get_key_btree_map() {
let (priv_key, pk) = gen_keys();
@@ -2379,7 +2379,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn pubkey_map_get_key_negates_odd_parity_keys() {
use crate::psbt::{GetKey, KeyRequest};
@@ -2536,7 +2536,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn hashmap_can_sign_taproot() {
let (priv_key, pk) = gen_keys();
let internal_key: XOnlyPublicKey = pk.inner.into();
@@ -2569,7 +2569,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn xonly_hashmap_can_sign_taproot() {
let (priv_key, pk) = gen_keys();
let internal_key: XOnlyPublicKey = pk.inner.into();
@@ -2602,7 +2602,7 @@ mod tests {
}
#[test]
- #[cfg(feature = "rand-std")]
+ #[cfg(all(feature = "rand", feature = "std"))]
fn sign_psbt() {
let unsigned_tx = Transaction {
version: transaction::Version::TWO,
diff --git a/bitcoin/src/sign_message.rs b/bitcoin/src/sign_message.rs
index 853ea565..8337bfe1 100644
--- a/bitcoin/src/sign_message.rs
+++ b/bitcoin/src/sign_message.rs
@@ -241,7 +241,7 @@ mod tests {
}
#[test]
- #[cfg(all(feature = "secp-recovery", feature = "base64", feature = "rand-std"))]
+ #[cfg(all(feature = "secp-recovery", feature = "base64", feature = "rand", feature = "std"))]
fn message_signature() {
use secp256k1::ecdsa::RecoverableSignature;
use crate::{Address, AddressType, Network, NetworkKind};
diff --git a/bitcoin/tests/psbt-sign-taproot.rs b/bitcoin/tests/psbt-sign-taproot.rs
index edeeb161..bd21a112 100644
--- a/bitcoin/tests/psbt-sign-taproot.rs
+++ b/bitcoin/tests/psbt-sign-taproot.rs
@@ -1,4 +1,6 @@
-#![cfg(not(feature = "rand-std"))]
+//! This test is excluded when the `rand` feature is enabled because Schnorr signatures use
+//! auxiliary randomness, making them non-deterministic and incompatible with hardcoded test vectors.
+#![cfg(all(feature = "std", not(feature = "rand")))]
use std::collections::BTreeMap;
Why this scored 18/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.