diff --git a/.travis.yml b/.travis.yml index 5030a8b..1f19070 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,9 @@ script: - cargo test --verbose --features="rand rand-std" - cargo test --verbose --features="rand serde" - cargo test --verbose --features="rand serde recovery endomorphism" + - if [ ${TRAVIS_RUST_VERSION} != "1.22.0" ]; then + cargo test --verbose --features global-context; + fi - cargo build --verbose - cargo test --verbose - cargo build --verbose --release diff --git a/Cargo.toml b/Cargo.toml index 3314622..be37c4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ rand-std = ["rand/std"] recovery = ["secp256k1-sys/recovery"] endomorphism = ["secp256k1-sys/endomorphism"] lowmemory = ["secp256k1-sys/lowmemory"] +global-context = [] # Use this feature to not compile the bundled libsecp256k1 C symbols, # but use external ones. Use this only if you know what you are doing! diff --git a/src/context.rs b/src/context.rs index 3ddf9a7..80290e6 100644 --- a/src/context.rs +++ b/src/context.rs @@ -9,6 +9,36 @@ use Secp256k1; #[cfg(feature = "std")] pub use self::std_only::*; +#[cfg(feature = "global-context")] +/// Module implementing a singleton pattern for a global `Secp256k1` context +pub mod global { + use std::ops::Deref; + use std::sync::Once; + use ::{Secp256k1, All}; + + /// Proxy struct for global `SECP256K1` context + pub struct GlobalContext { + __private: (), + } + + /// A global, static context to avoid repeatedly creating contexts where one can't be passed + pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; + + impl Deref for GlobalContext { + type Target = Secp256k1; + + 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() } + } + } +} + + /// A trait for all kinds of Context's that Lets you define the exact flags and a function to deallocate memory. /// It shouldn't be possible to implement this for types outside this crate. pub unsafe trait Context : private::Sealed { diff --git a/src/lib.rs b/src/lib.rs index bb16853..7361226 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,6 +179,9 @@ use core::marker::PhantomData; use core::ops::Deref; use ffi::CPtr; +#[cfg(feature = "global-context")] +pub use context::global::SECP256K1; + #[cfg(feature = "bitcoin_hashes")] use bitcoin_hashes::Hash; @@ -1138,6 +1141,24 @@ mod tests { assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]); } + #[cfg(feature = "global-context")] + #[test] + fn test_global_context() { + use super::SECP256K1; + + let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641"); + let sk = SecretKey::from_slice(&sk_data).unwrap(); + let msg_data = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); + let msg = Message::from_slice(&msg_data).unwrap(); + + // Check usage as explicit parameter + let pk = PublicKey::from_secret_key(&SECP256K1, &sk); + + // Check usage as self + let sig = SECP256K1.sign(&msg, &sk); + assert!(SECP256K1.verify(&msg, &sig, &pk).is_ok()); + } + // For WASM, just run through our general tests in this file all at once. #[cfg(target_arch = "wasm32")] extern crate wasm_bindgen_test;