@@ -8,6 +8,98 @@ use crate::ffi::types::{c_uint, c_void, AlignedType};
8
8
use crate :: ffi:: { self , CPtr } ;
9
9
use crate :: { Error , Secp256k1 } ;
10
10
11
+ // This module will be renamed to `global` in later commit which eliminates the other `global` module
12
+ #[ cfg( feature = "std" ) ]
13
+ pub mod global_ {
14
+ use core:: cell:: RefCell ;
15
+ use crate :: { ffi, All , Secp256k1 } ;
16
+
17
+ thread_local ! {
18
+ pub static CONTEXT : RefCell <Secp256k1 <All >> = RefCell :: new( Secp256k1 :: new( ) ) ;
19
+ }
20
+
21
+ /// Do some operation using an immutable reference to the global signing context
22
+ ///
23
+ /// Safety: you are being given a raw pointer. Do not mutate through it. Do not
24
+ /// move it, or any reference to it, across thread boundaries.
25
+ pub unsafe fn with_global_context < F : FnOnce ( * const ffi:: Context ) -> R , R > ( f : F ) -> R {
26
+ CONTEXT . with ( |refcell| f ( refcell. borrow ( ) . ctx as * const _ ) )
27
+ }
28
+
29
+ /// Rerandomize the global signing context
30
+ ///
31
+ /// # Panics
32
+ ///
33
+ /// Will panic if called from a closure passed to `with_global_ctx`.
34
+ pub fn rerandomize_context ( seed : & [ u8 ; 32 ] ) {
35
+ CONTEXT . with ( |refcell| {
36
+ let borrow = refcell. borrow_mut ( ) ;
37
+ let bare = borrow. ctx ;
38
+ unsafe {
39
+ let ret = ffi:: secp256k1_context_randomize ( bare, seed. as_ptr ( ) ) ;
40
+ assert_eq ! ( ret, 1 ) ; // sanity check: context_randomize cannot fail
41
+ }
42
+ } ) ;
43
+ }
44
+ }
45
+
46
+ #[ cfg( not( feature = "std" ) ) ]
47
+ mod global_ {
48
+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
49
+ use crate :: ffi;
50
+
51
+ static LOCK : AtomicBool = AtomicBool :: new ( false ) ;
52
+
53
+ // Safety: all of the unsafe blocks in this module are due to our accessing
54
+ // extern statics (the ffi::* context objects). Rust cannot control access
55
+ // to these, so we need unsafe.
56
+ //
57
+ // In particular, we are promising here that nothing else will concurrently
58
+ // access ffi::secp256k1_context_signing_{1, 2} ... though in principle,
59
+ // any code that can see the `ffi` module will be able to do so. We can only
60
+ // make promises about our own code.
61
+ //
62
+ // Other accessors, who to be clear SHOULD NOT EXIST, will need their own
63
+ // unsafe block. As far as I know this is the best we can do.
64
+
65
+ /// Do some operation using an immutable reference to the global signing context
66
+ pub unsafe fn with_global_ctx < F : FnOnce ( * const ffi:: Context ) -> R , R > ( f : F ) -> R {
67
+ let ctx = unsafe { ffi:: secp256k1_context_signing_1. load ( Ordering :: Acquire ) } ;
68
+ f ( ctx as * const _ )
69
+ }
70
+
71
+ /// Do some operation using a mutable reference to the global signing context
72
+ pub fn rerandomize_context ( seed : & [ u8 ; 32 ] ) {
73
+ if LOCK . swap ( true , Ordering :: Acquire ) {
74
+ // Concurrent operation in progress; give up
75
+ return ;
76
+ }
77
+
78
+ unsafe {
79
+ // Obtain a pointer to the alternate context.
80
+ let alt_ctx = ffi:: secp256k1_context_signing_2. load ( Ordering :: Acquire ) ;
81
+ // Obtain a pointer to the signing context, atomically replacing it with
82
+ // the alternate signing context (which never gets modified). Any concurrent
83
+ // callers to `with_global_ctx` will see the alternate context, not any
84
+ // inconsistent state of this one.
85
+ //
86
+ // (Concurrent callers to `with_global_ctx_mut` will fail after checking `LOCK`.).
87
+ let ctx = ffi:: secp256k1_context_signing_1. swap ( alt_ctx, Ordering :: Acquire ) ;
88
+ // Do the rerandomization. Note that unlike in the `std` case, we don't
89
+ // panic if this function fails (which again, it is guaranteed not to).
90
+ // The reason is that a panic at this point in the code would leave
91
+ // `LOCK` at true (as well as both `signing_1` and `signing_2` pointing
92
+ // at the same, never-rerandomized, place) and therefore prevent any
93
+ // future rerandomizations from succeeding.
94
+ ffi:: secp256k1_context_randomize ( ctx, seed. as_ptr ( ) ) ;
95
+ // Atomically swap completely-modified context into place
96
+ ffi:: secp256k1_context_signing_1. swap ( ctx, Ordering :: Release ) ;
97
+ } ;
98
+
99
+ LOCK . store ( false , Ordering :: Release ) ;
100
+ }
101
+ }
102
+
11
103
#[ cfg( all( feature = "global-context" , feature = "std" ) ) ]
12
104
#[ cfg_attr( docsrs, doc( cfg( all( feature = "global-context" , feature = "std" ) ) ) ) ]
13
105
/// Module implementing a singleton pattern for a global `Secp256k1` context.
0 commit comments