diff --git a/Cargo.toml b/Cargo.toml index 7bff8fada..a9444ef53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,18 +16,9 @@ exclude = ["tests", "contrib"] [features] default = ["std"] std = ["alloc", "secp256k1-sys/std", "rand?/std", "rand?/std_rng", "rand?/thread_rng"] -# allow use of Secp256k1::new and related API that requires an allocator alloc = ["secp256k1-sys/alloc"] recovery = ["secp256k1-sys/recovery"] lowmemory = ["secp256k1-sys/lowmemory"] -global-context = ["std"] -# disable re-randomization of the global context, which provides some -# defense-in-depth against sidechannel attacks. You should only use -# this feature if you expect the `rand` crate's thread_rng to panic. -# (If you are sure the `rand` and `std` features will not be enabled, e.g. -# if you are doing a no-std build, then this feature does nothing -# and is not necessary.) -global-context-less-secure = ["global-context"] arbitrary = ["dep:arbitrary"] [dependencies] diff --git a/contrib/test_vars.sh b/contrib/test_vars.sh index 33b22d25a..2b9710547 100644 --- a/contrib/test_vars.sh +++ b/contrib/test_vars.sh @@ -5,10 +5,10 @@ # shellcheck disable=SC2034 # Test all these features with "std" enabled. -FEATURES_WITH_STD="global-context global-context-less-secure lowmemory rand recovery serde" +FEATURES_WITH_STD="lowmemory rand recovery serde" # Test all these features without "std" enabled. -FEATURES_WITHOUT_STD="global-context global-context-less-secure lowmemory rand recovery serde alloc" +FEATURES_WITHOUT_STD="lowmemory rand recovery serde alloc" # Run these examples. EXAMPLES="sign_verify:std sign_verify_recovery:std,recovery generate_keys:rand,std" diff --git a/githooks/pre-commit b/githooks/pre-commit index c42944236..07b34ea2c 100755 --- a/githooks/pre-commit +++ b/githooks/pre-commit @@ -47,7 +47,7 @@ fi git diff-index --check --cached "$against" -- || exit 1 # Check that code lints cleanly. -cargo clippy --features=rand,std,recovery,lowmemory,global-context --all-targets -- -D warnings || exit 1 +cargo clippy --features=rand,std,recovery,lowmemory --all-targets -- -D warnings || exit 1 # Check that there are no formatting issues. cargo +nightly fmt --check || exit 1 diff --git a/src/context/internal_nostd.rs b/src/context/internal_nostd.rs index 2af5efebd..5ecc503ec 100644 --- a/src/context/internal_nostd.rs +++ b/src/context/internal_nostd.rs @@ -17,6 +17,7 @@ mod self_contained_context { const MAX_PREALLOC_SIZE: usize = 16; // measured at 208 bytes on Andrew's 64-bit system /// A secp256k1 context object which can be allocated on the stack or in static storage. + #[derive(Debug)] pub struct SelfContainedContext( [MaybeUninit; MAX_PREALLOC_SIZE], Option>, @@ -73,7 +74,8 @@ mod self_contained_context { // because we need a const constructor.) pub(super) use self_contained_context::SelfContainedContext; -static SECP256K1: SpinLock = SpinLock::::new(); +/// A global static context to avoid repeatedly creating contexts. +pub static SECP256K1: SpinLock = SpinLock::::new(); /// Borrows the global context and does some operation on it. /// diff --git a/src/context/internal_std.rs b/src/context/internal_std.rs index 5fc8f3c2c..6d23b0a89 100644 --- a/src/context/internal_std.rs +++ b/src/context/internal_std.rs @@ -10,7 +10,10 @@ use secp256k1_sys as ffi; use crate::{All, Context, Secp256k1}; thread_local! { - static SECP256K1: RefCell> = RefCell::new(Secp256k1::new()); + /// A global static context to avoid repeatedly creating contexts. + /// + /// If `rand` feature is enabled, context will have been randomized using `rng`. + pub static SECP256K1: RefCell> = RefCell::new(Secp256k1::new()); } /// Borrows the global context and does some operation on it. diff --git a/src/context/mod.rs b/src/context/mod.rs index ea57cc58e..9e1dea45a 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -17,45 +17,9 @@ mod internal; #[cfg(not(feature = "std"))] mod spinlock; -pub use internal::{rerandomize_global_context, with_global_context, with_raw_global_context}; - -#[cfg(all(feature = "global-context", feature = "std"))] -/// Module implementing a singleton pattern for a global `Secp256k1` context. -pub mod global { - - use std::ops::Deref; - use std::sync::Once; - - use crate::{All, Secp256k1}; - - /// Proxy struct for global `SECP256K1` context. - #[derive(Debug, Copy, Clone)] - pub struct GlobalContext { - __private: (), - } - - /// A global static context to avoid repeatedly creating contexts. - /// - /// If `rand` and `std` feature is enabled, context will have been randomized using - /// `rng`. - pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; - - impl Deref for GlobalContext { - type Target = Secp256k1; - - #[allow(unused_mut)] // Unused when `rand` + `std` is not enabled. - #[allow(static_mut_refs)] // The "proper" way to do this is with OnceLock (MSRV 1.70) or LazyLock (MSRV 1.80) - // See https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html - fn deref(&self) -> &Self::Target { - static ONCE: Once = Once::new(); - static mut CONTEXT: Option> = None; - ONCE.call_once(|| unsafe { - CONTEXT = Some(Secp256k1::new()); - }); - unsafe { CONTEXT.as_ref().unwrap() } - } - } -} +pub use internal::{ + rerandomize_global_context, with_global_context, with_raw_global_context, SECP256K1, +}; /// A trait for all kinds of contexts that lets you define the exact flags and a function to /// deallocate memory. It isn't possible to implement this for types outside this crate. @@ -213,12 +177,7 @@ mod alloc_only { phantom: PhantomData, }; - #[cfg(all( - not(target_arch = "wasm32"), - feature = "rand", - feature = "std", - not(feature = "global-context-less-secure") - ))] + #[cfg(all(not(target_arch = "wasm32"), feature = "rand", feature = "std",))] { ctx.randomize(&mut rand::rng()); } diff --git a/src/context/spinlock.rs b/src/context/spinlock.rs index bf4d55afc..ca832e435 100644 --- a/src/context/spinlock.rs +++ b/src/context/spinlock.rs @@ -23,6 +23,7 @@ const MAX_SPINLOCK_ATTEMPTS: usize = 128; // new stack-local context object if we are unable to obtain a lock on the // global one. This is slow and loses the defense-in-depth "rerandomization" // anti-sidechannel measure, but it is better than deadlocking.. +#[derive(Debug)] pub struct SpinLock { flag: AtomicBool, // Invariant: if this is non-None, then the store is valid and can be @@ -83,6 +84,7 @@ impl SpinLock { } /// Drops the lock when it goes out of scope. +#[derive(Debug)] pub struct SpinLockGuard<'a, T> { lock: &'a SpinLock, } diff --git a/src/ecdsa/recovery.rs b/src/ecdsa/recovery.rs index 6f507e64c..9b1b02c92 100644 --- a/src/ecdsa/recovery.rs +++ b/src/ecdsa/recovery.rs @@ -128,7 +128,6 @@ impl RecoverableSignature { /// Determines the public key for which this [`Signature`] is valid for `msg`. Requires a /// verify-capable context. #[inline] - #[cfg(feature = "global-context")] pub fn recover(&self, msg: impl Into) -> Result { self.recover_ecdsa(msg) } diff --git a/src/key/mod.rs b/src/key/mod.rs index b80315b84..069569b0c 100644 --- a/src/key/mod.rs +++ b/src/key/mod.rs @@ -115,12 +115,6 @@ impl PublicKey { #[inline] pub fn from_ellswift(ellswift: ElligatorSwift) -> PublicKey { ElligatorSwift::decode(ellswift) } - /// Creates a new public key from a [`SecretKey`]. - #[inline] - #[cfg(feature = "global-context")] - #[deprecated(since = "TBD", note = "use from_secret_key instead")] - pub fn from_secret_key_global(sk: &SecretKey) -> PublicKey { PublicKey::from_secret_key(sk) } - /// Creates a public key directly from a slice. #[inline] pub fn from_slice(data: &[u8]) -> Result { @@ -460,7 +454,7 @@ impl<'de> serde::Deserialize<'de> for PublicKey { /// /// # Serde support /// -/// Implements de/serialization with the `serde` and `global-context` features enabled. Serializes +/// Implements de/serialization with the `serde` and feature enabled. Serializes /// the secret bytes only. We treat the byte value as a tuple of 32 `u8`s for non-human-readable /// formats. This representation is optimal for some formats (e.g. [`bincode`]) however other /// formats may be less optimal (e.g. [`cbor`]). For human-readable formats we use a hex string. @@ -552,16 +546,6 @@ impl Keypair { #[deprecated(note = "use FromStr or parse instead")] pub fn from_seckey_str(s: &str) -> Result { s.parse() } - /// Creates a [`Keypair`] directly from a secret key string. - /// - /// # Errors - /// - /// [`Error::InvalidSecretKey`] if the string does not consist of exactly 64 hex characters, - /// or if the encoded number is an invalid scalar. - #[inline] - #[deprecated(note = "use FromStr or parse instead")] - pub fn from_seckey_str_global(s: &str) -> Result { s.parse() } - /// Generates a new random key pair. /// # Examples /// @@ -606,7 +590,7 @@ impl Keypair { /// Generates a new random secret key. #[inline] - #[cfg(all(feature = "global-context", feature = "rand"))] + #[cfg(feature = "rand")] #[deprecated(since = "TBD", note = "use Keypair::new instead")] pub fn new_global(rng: &mut R) -> Keypair { Keypair::new(rng) } @@ -1939,13 +1923,12 @@ mod test { } #[test] - #[cfg(all(feature = "global-context", feature = "serde"))] + #[cfg(feature = "serde")] fn test_serde_keypair() { use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_test::{assert_tokens, Configure, Token}; use crate::key::Keypair; - use crate::SECP256K1; #[rustfmt::skip] static SK_BYTES: [u8; 32] = [ @@ -2115,7 +2098,7 @@ mod test { #[test] #[cfg(not(secp256k1_fuzz))] - #[cfg(all(feature = "global-context", feature = "serde"))] + #[cfg(feature = "serde")] fn test_serde_x_only_pubkey() { use serde_test::{assert_tokens, Configure, Token}; diff --git a/src/lib.rs b/src/lib.rs index f7d05cb43..3160e6eb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,26 +49,6 @@ //! # } //! ``` //! -//! If the "global-context" feature is enabled you have access to an alternate API. -//! -//! ```rust -//! # #[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] { -//! use secp256k1::{rand, Message}; -//! -//! // See previous example regarding this constant. -//! const HELLO_WORLD_SHA2: [u8; 32] = [ -//! 0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0, 0x06, 0x4e, 0x4a, 0x01, 0x64, -//! 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8, 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3, -//! ]; -//! -//! let (secret_key, public_key) = secp256k1::generate_keypair(&mut rand::rng()); -//! let message = Message::from_digest(HELLO_WORLD_SHA2); -//! -//! let sig = secret_key.sign_ecdsa(message); -//! assert!(sig.verify(message, &public_key).is_ok()); -//! # } -//! ``` -//! //! The above code requires `rust-secp256k1` to be compiled with the `rand`, `hashes`, and `std` //! feature enabled, to get access to [`generate_keypair`](struct.Secp256k1.html#method.generate_keypair) //! Alternately, keys and messages can be parsed from slices, like @@ -139,7 +119,6 @@ //! * `hashes` - use the `hashes` library. //! * `recovery` - enable functions that can compute the public key from signature. //! * `lowmemory` - optimize the library for low-memory environments. -//! * `global-context` - enable use of global secp256k1 context (implies `std`). //! * `serde` - implements serialization and deserialization for types in this crate using `serde`. //! **Important**: `serde` encoding is **not** the same as consensus encoding! //! @@ -191,8 +170,7 @@ use crate::ffi::CPtr; #[rustfmt::skip] // Keep public re-exports separate. pub use secp256k1_sys as ffi; -#[cfg(all(feature = "global-context", feature = "std"))] -pub use crate::context::global::{self, SECP256K1}; +pub use crate::context::SECP256K1; #[cfg(feature = "alloc")] pub use crate::context::{All, SignOnly, VerifyOnly}; #[doc(inline)] @@ -423,12 +401,12 @@ pub fn generate_keypair(rng: &mut R) -> (key::SecretKey, /// Constructor for unit testing. (Calls `generate_keypair` if all /// the relevant features are on to get coverage of that functoin.) #[cfg(test)] -#[cfg(all(feature = "global-context", feature = "rand", feature = "std"))] +#[cfg(all(feature = "rand", feature = "std"))] fn test_random_keypair() -> (key::SecretKey, key::PublicKey) { generate_keypair(&mut rand::rng()) } /// Constructor for unit testing. #[cfg(test)] -#[cfg(not(all(feature = "global-context", feature = "rand", feature = "std")))] +#[cfg(not(all(feature = "rand", feature = "std")))] fn test_random_keypair() -> (key::SecretKey, key::PublicKey) { let sk = SecretKey::test_random(); let pk = key::PublicKey::from_secret_key(&sk); @@ -964,7 +942,6 @@ mod tests { assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]); } - #[cfg(feature = "global-context")] #[test] fn test_global_context() { let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641"); diff --git a/src/schnorr.rs b/src/schnorr.rs index 5db8afc66..75760ce0c 100644 --- a/src/schnorr.rs +++ b/src/schnorr.rs @@ -103,7 +103,6 @@ impl Signature { /// Verifies a schnorr signature for `msg` using `pk`. #[inline] - #[cfg(feature = "global-context")] pub fn verify(&self, msg: &[u8], pk: &XOnlyPublicKey) -> Result<(), Error> { verify(self, msg, pk) } diff --git a/src/secret.rs b/src/secret.rs index 8abb079d9..20e053058 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -131,9 +131,8 @@ impl Keypair { /// ``` /// # #[cfg(feature = "std")] { /// # use std::str::FromStr; - /// use secp256k1::{Keypair, Secp256k1, SecretKey}; + /// use secp256k1::{Keypair, SecretKey}; /// - /// let secp = Secp256k1::new(); /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); /// let key = Keypair::from_secret_key(&key); /// // Here we explicitly display the secret value: diff --git a/tests/serde.rs b/tests/serde.rs index 63a9aea14..7c7123b3e 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -4,9 +4,7 @@ extern crate bincode; extern crate secp256k1; extern crate serde_cbor; -#[cfg(feature = "global-context")] -use secp256k1::Keypair; -use secp256k1::{musig, PublicKey, SecretKey, XOnlyPublicKey}; +use secp256k1::{musig, Keypair, PublicKey, SecretKey, XOnlyPublicKey}; // Arbitrary key data. @@ -95,7 +93,6 @@ fn bincode_public_key() { } #[test] -#[cfg(feature = "global-context")] fn bincode_keypair() { let kp = Keypair::from_seckey_byte_array(SK_BYTES).expect("failed to create keypair"); let ser = bincode::serialize(&kp).unwrap();