Skip to content

Commit

Permalink
Merge pull request #224 from sgeisler/2020-07-global-context
Browse files Browse the repository at this point in the history
Add an optional global, static context
  • Loading branch information
apoelstra committed Aug 7, 2020
2 parents c9741d4 + 2046a40 commit c6ab14b
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -29,6 +29,7 @@ rand-std = ["rand/std"]
recovery = ["secp256k1-sys/recovery"]
endomorphism = ["secp256k1-sys/endomorphism"]
lowmemory = ["secp256k1-sys/lowmemory"]
global-context = ["std", "rand"]

# 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!
Expand Down
32 changes: 32 additions & 0 deletions src/context.rs
Expand Up @@ -9,6 +9,38 @@ 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<All>;

fn deref(&self) -> &Self::Target {
static ONCE: Once = Once::new();
static mut CONTEXT: Option<Secp256k1<All>> = None;
ONCE.call_once(|| unsafe {
let mut ctx = Secp256k1::new();
ctx.randomize(&mut rand::thread_rng());
CONTEXT = Some(ctx);
});
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 {
Expand Down
21 changes: 21 additions & 0 deletions src/lib.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit c6ab14b

Please sign in to comment.