Skip to content

Commit c6ab14b

Browse files
authored
Merge pull request #224 from sgeisler/2020-07-global-context
Add an optional global, static context
2 parents c9741d4 + 2046a40 commit c6ab14b

File tree

4 files changed

+57
-0
lines changed

4 files changed

+57
-0
lines changed

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ script:
4343
- cargo test --verbose --features="rand rand-std"
4444
- cargo test --verbose --features="rand serde"
4545
- cargo test --verbose --features="rand serde recovery endomorphism"
46+
- if [ ${TRAVIS_RUST_VERSION} != "1.22.0" ]; then
47+
cargo test --verbose --features global-context;
48+
fi
4649
- cargo build --verbose
4750
- cargo test --verbose
4851
- cargo build --verbose --release

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ rand-std = ["rand/std"]
2929
recovery = ["secp256k1-sys/recovery"]
3030
endomorphism = ["secp256k1-sys/endomorphism"]
3131
lowmemory = ["secp256k1-sys/lowmemory"]
32+
global-context = ["std", "rand"]
3233

3334
# Use this feature to not compile the bundled libsecp256k1 C symbols,
3435
# but use external ones. Use this only if you know what you are doing!

src/context.rs

+32
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,38 @@ use Secp256k1;
99
#[cfg(feature = "std")]
1010
pub use self::std_only::*;
1111

12+
#[cfg(feature = "global-context")]
13+
/// Module implementing a singleton pattern for a global `Secp256k1` context
14+
pub mod global {
15+
use std::ops::Deref;
16+
use std::sync::Once;
17+
use ::{Secp256k1, All};
18+
19+
/// Proxy struct for global `SECP256K1` context
20+
pub struct GlobalContext {
21+
__private: (),
22+
}
23+
24+
/// A global, static context to avoid repeatedly creating contexts where one can't be passed
25+
pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () };
26+
27+
impl Deref for GlobalContext {
28+
type Target = Secp256k1<All>;
29+
30+
fn deref(&self) -> &Self::Target {
31+
static ONCE: Once = Once::new();
32+
static mut CONTEXT: Option<Secp256k1<All>> = None;
33+
ONCE.call_once(|| unsafe {
34+
let mut ctx = Secp256k1::new();
35+
ctx.randomize(&mut rand::thread_rng());
36+
CONTEXT = Some(ctx);
37+
});
38+
unsafe { CONTEXT.as_ref().unwrap() }
39+
}
40+
}
41+
}
42+
43+
1244
/// A trait for all kinds of Context's that Lets you define the exact flags and a function to deallocate memory.
1345
/// It shouldn't be possible to implement this for types outside this crate.
1446
pub unsafe trait Context : private::Sealed {

src/lib.rs

+21
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ use core::marker::PhantomData;
179179
use core::ops::Deref;
180180
use ffi::CPtr;
181181

182+
#[cfg(feature = "global-context")]
183+
pub use context::global::SECP256K1;
184+
182185
#[cfg(feature = "bitcoin_hashes")]
183186
use bitcoin_hashes::Hash;
184187

@@ -1138,6 +1141,24 @@ mod tests {
11381141
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
11391142
}
11401143

1144+
#[cfg(feature = "global-context")]
1145+
#[test]
1146+
fn test_global_context() {
1147+
use super::SECP256K1;
1148+
1149+
let sk_data = hex!("e6dd32f8761625f105c39a39f19370b3521d845a12456d60ce44debd0a362641");
1150+
let sk = SecretKey::from_slice(&sk_data).unwrap();
1151+
let msg_data = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d");
1152+
let msg = Message::from_slice(&msg_data).unwrap();
1153+
1154+
// Check usage as explicit parameter
1155+
let pk = PublicKey::from_secret_key(&SECP256K1, &sk);
1156+
1157+
// Check usage as self
1158+
let sig = SECP256K1.sign(&msg, &sk);
1159+
assert!(SECP256K1.verify(&msg, &sig, &pk).is_ok());
1160+
}
1161+
11411162
// For WASM, just run through our general tests in this file all at once.
11421163
#[cfg(target_arch = "wasm32")]
11431164
extern crate wasm_bindgen_test;

0 commit comments

Comments
 (0)