@@ -10,6 +10,108 @@ use crate::ffi::types::{c_uint, c_void, AlignedType};
10
10
use crate :: ffi:: { self , CPtr } ;
11
11
use crate :: { Error , Secp256k1 } ;
12
12
13
+ #[ cfg( feature = "std" ) ]
14
+ mod internal {
15
+ use std:: cell:: RefCell ;
16
+ use std:: marker:: PhantomData ;
17
+ use std:: mem:: ManuallyDrop ;
18
+ use std:: ptr:: NonNull ;
19
+
20
+ use secp256k1_sys as ffi;
21
+
22
+ use crate :: { All , Context , Secp256k1 } ;
23
+
24
+ thread_local ! {
25
+ static SECP256K1 : RefCell <Secp256k1 <All >> = RefCell :: new( Secp256k1 :: new( ) ) ;
26
+ static RAND_SEED : RefCell <[ u8 ; 32 ] > = const { RefCell :: new( [ 0 ; 32 ] ) } ;
27
+ }
28
+
29
+ /// Borrows the global context and do some operation on it.
30
+ ///
31
+ /// If provided, after the operation is complete, [`rerandomize_global_context`]
32
+ /// is called on the context. If you have some random data available,
33
+ pub fn with_global_context < T , Ctx : Context , F : FnOnce ( & Secp256k1 < Ctx > ) -> T > (
34
+ f : F ,
35
+ rerandomize_seed : Option < & [ u8 ; 32 ] > ,
36
+ ) -> T {
37
+ with_raw_global_context (
38
+ |ctx| {
39
+ let secp = ManuallyDrop :: new ( Secp256k1 { ctx, phantom : PhantomData } ) ;
40
+ f ( & * secp)
41
+ } ,
42
+ rerandomize_seed,
43
+ )
44
+ }
45
+
46
+ /// Borrows the global context as a raw pointer and do some operation on it.
47
+ ///
48
+ /// If provided, after the operation is complete, [`rerandomize_global_context`]
49
+ /// is called on the context. If you have some random data available,
50
+ pub fn with_raw_global_context < T , F : FnOnce ( NonNull < ffi:: Context > ) -> T > (
51
+ f : F ,
52
+ rerandomize_seed : Option < & [ u8 ; 32 ] > ,
53
+ ) -> T {
54
+ SECP256K1 . with ( |secp| {
55
+ let borrow = secp. borrow ( ) ;
56
+ let ret = f ( borrow. ctx ) ;
57
+ drop ( borrow) ;
58
+
59
+ if let Some ( seed) = rerandomize_seed {
60
+ rerandomize_global_context ( seed) ;
61
+ }
62
+ ret
63
+ } )
64
+ }
65
+
66
+ /// Rerandomize the global context, using the given data as a seed.
67
+ ///
68
+ /// The provided data will be mixed with the entropy from previous calls in a timing
69
+ /// analysis resistant way. It is safe to directly pass secret data to this function.
70
+ pub fn rerandomize_global_context ( seed : & [ u8 ; 32 ] ) {
71
+ SECP256K1 . with ( |secp| {
72
+ RAND_SEED . with ( |rand_seed| {
73
+ let mut old_seed = rand_seed. borrow_mut ( ) ;
74
+ let mut new_seed = [ 0 ; 32 ] ;
75
+ // We don't have direct access to sha256 except through the default nonce
76
+ // functions. The ECDSA one uses RFC6979 which is absurdly slow, but the
77
+ // Schnorr one is not too bad.
78
+ unsafe {
79
+ assert_eq ! (
80
+ ( ffi:: secp256k1_nonce_function_bip340. unwrap( ) ) (
81
+ new_seed. as_mut_ptr( ) ,
82
+ seed. as_ptr( ) , // msg
83
+ seed. len( ) , // msg len
84
+ old_seed. as_ptr( ) , // key32
85
+ old_seed. as_ptr( ) , // xonly_pk32
86
+ b"rust-secp-randomize" . as_ptr( ) ,
87
+ b"rust-secp-randomize" . len( ) ,
88
+ core:: ptr:: null_mut( ) ,
89
+ ) ,
90
+ 1 ,
91
+ "calling bip340 nonce function failed" ,
92
+ ) ;
93
+ }
94
+
95
+ // If we have access to the thread rng then use it as well.
96
+ #[ cfg( feature = "rand" ) ]
97
+ {
98
+ let mask: [ u8 ; 32 ] = rand:: random ( ) ;
99
+ for ( byte, mask) in new_seed. iter_mut ( ) . zip ( mask. iter ( ) ) {
100
+ * byte ^= * mask;
101
+ }
102
+ }
103
+
104
+ // Actual rerandomization
105
+ let mut borrow = secp. borrow_mut ( ) ;
106
+ borrow. seeded_randomize ( & new_seed) ;
107
+ old_seed. copy_from_slice ( & new_seed) ;
108
+ } ) ;
109
+ } ) ;
110
+ }
111
+ }
112
+ #[ cfg( feature = "std" ) ]
113
+ pub use internal:: { rerandomize_global_context, with_global_context, with_raw_global_context} ;
114
+
13
115
#[ cfg( all( feature = "global-context" , feature = "std" ) ) ]
14
116
/// Module implementing a singleton pattern for a global `Secp256k1` context.
15
117
pub mod global {
0 commit comments